You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
cancelScheduledValues with setValueCurveAtTime #2071
Describe the issue
Consider the following bit of code:
time = ctx.currentTime;
gain.gain.setValueCurveAtTime(curve, time + 0.1, 1);
gain.gain.cancelScheduledValues(time + 0.2);
gain.gain.setValueCurveAtTime(curve, time + 0.3, 1);
The second call to setValueCurveAtTime will throw an error because it overlaps the first. Basically cancelScheduledValues didn't remove the first setValueCurveAtTime.
A strict reading of the spec says this is the correct behavior because the event time of the first setValueCurve is time + 0.1, which is before the cancel time of time + 0.2. Hence it isn't removed.
The result is that you can't actually remove a setValueCurve; you have to wait until after the setValueCurve has ended before scheduling anything else.
The spec is pretty clear on what the behavior is, but I think we do really want to be able to remove the setValueCurve event if it ends some time after the cancel time.
setTargetAtTime kind of has the same issue, but you can always schedule events after it without errors, so perhaps we don't need to do anything here for that.
Wouldn't it be possible to use cancelAndHoldAtTime() instead of cancelScheduledValues()? It will truncate the curve which makes it possible to schedule another curve right away.
Yes, cancelAndHoldAtTime would do something useful. Not quite the same as cancelScheduledValues, though.
The alternative that would work is to use the same time for cancelScheduledValues as was used for the setValueCurveAtTime. Maybe that is the answer we're looking for here?
Cancels all scheduled parameter changes with times greater than or equal to cancelTime. Cancelling a scheduled parameter change means removing the scheduled event from the event list. Any active automations whose automation event time is less than cancelTime are also cancelled, and such cancellations may cause discontinuities because the original value (from before such automation) is restored immediately. Any hold values scheduled by cancelAndHoldAtTime() are also removed if the hold time occurs after cancelTime.
My interpretation of the bolded part is that setValueCurveAtTime(curve, t, 1) should be aborted by cancelScheduledValues(t + 0.1), unless value curves aren't considered automations? If that's the case it doesn't appear to be possible to cancel already started curves, since the cancelScheduledValues(cancelTime) argument is clamped to >=currentTime:
If cancelTime is less than currentTime, it is clamped to currentTime.
conststart=ctx.currentTimegain.gain.setValueCurveAtTime(curve1,start,1)setTimeout(()=>{constcancelTime=ctx.currentTime// both `0` and `start` are clamped to ctx.currentTime according to the specgain.gain.cancelScheduledValues(cancelTime)gain.gain.setValueCurveAtTime(curve2,ctx.currentTime,1)},100)
Current browser behaviour for the above code
Firefox v68
Throws Operation is not supported when cancelTime is 0, start or ctx.currentTime.
Haven't found any working values.
Chrome v77
Any value less than ctx.currentTime appears to work (0, start, ctx.currentTime - 0.01).
Using ctx.currentTime throws Failed to execute 'setValueCurveAtTime' on 'AudioParam': setValueCurveAtTime(...) overlaps setValueCurveAtTime(...).
Edge v42
All values 0 <= cancelTime <= ctx.currentTime appear to work.
Oh, you are right about the bold part of the spec. I missed that on my initial read. I think that means setValueCurveAtTime event will be removed as well as a setTargetAtTime. That will make your use case work better.
However, I'm not sure what should happen if the setValueCurveAtTime is being processed when cancelScheduledValues is called and the setValueCurve event is removed. What is the param value then? Same question for setTargetAtTime.
Teleconf: @rtoy to come up with a proposal on how this works. Probably will remove the setCurve if the cancel time lies between the start and duration of the setCurve. Not a problem for setTarget where you can always schedule something after a setTarget.
I think we need to consider what it means to be an "active automation".
My interpretation is that at the time cancelScheduledValues is called the automation is running, and we're canceling events that includes the the currently running event. Something like the following (that can be run using https://hoch.github.io/canopy):
// @channels 1
// @duration 1.0
// @sampleRate 44100
var osc = new ConstantSourceNode(context);
var gain = context.createGain();
osc.offset.setValueAtTime(0, 0.0);
osc.offset.linearRampToValueAtTime(2, .5);
context.suspend(.3)
.then(() => osc.offset.cancelScheduledValues(.4))
.then(() => context.resume());
osc.connect(gain).connect(context.destination);
osc.start();
At time 0.3, we call cancelScheduledValues(0.4) and the resulting
curve stops increasing and holds at the value it had at time 0.3.
the output is a constant 1 up to time 0.5 and then becomes a constant 0.
For setValueCurve, I think it might be best if cancelScheduledValues is called before the start of the setValueCurve, and if the cancel time is in the middle of the setValueCurve, the entire curve event is removed.
If cancelScheduledValues is called when the curve is running, and the cancel time is in the middle of the curve, maybe the right thing would be to remove the curve event, and then replace it with a setValueAtTime event whose value is equal to the curve output at the cancel time. This is a bit complicated, but kind of matches how the linearRamp example above works.
The behavior in the first snippet from #2071 (comment) isn't specified any where that I can find. I don't want to specify that now, so I'm not going to add anything about that for setValueCurve.
But I will make it explicit that if the cancel time is in the middle of the curve, the entire curve event is removed.
Activity
chrisguttandin commentedon Oct 2, 2019
Wouldn't it be possible to use
cancelAndHoldAtTime()instead ofcancelScheduledValues()? It will truncate the curve which makes it possible to schedule another curve right away.rtoy commentedon Oct 3, 2019
Yes,
cancelAndHoldAtTimewould do something useful. Not quite the same ascancelScheduledValues, though.The alternative that would work is to use the same time for
cancelScheduledValuesas was used for thesetValueCurveAtTime. Maybe that is the answer we're looking for here?mogelbrod commentedon Oct 3, 2019
Author of the StackOverflow question here.
From the cancelScheduledValues() spec:
My interpretation of the bolded part is that
setValueCurveAtTime(curve, t, 1)should be aborted bycancelScheduledValues(t + 0.1), unless value curves aren't considered automations? If that's the case it doesn't appear to be possible to cancel already started curves, since thecancelScheduledValues(cancelTime)argument is clamped to>=currentTime:Current browser behaviour for the above code
Firefox v68
Throws Operation is not supported when
cancelTimeis0,startorctx.currentTime.Haven't found any working values.
Chrome v77
Any value less than
ctx.currentTimeappears to work (0,start,ctx.currentTime - 0.01).Using
ctx.currentTimethrows Failed to execute 'setValueCurveAtTime' on 'AudioParam': setValueCurveAtTime(...) overlaps setValueCurveAtTime(...).Edge v42
All values
0 <= cancelTime <= ctx.currentTimeappear to work.rtoy commentedon Oct 3, 2019
Oh, you are right about the bold part of the spec. I missed that on my initial read. I think that means
setValueCurveAtTimeevent will be removed as well as asetTargetAtTime. That will make your use case work better.However, I'm not sure what should happen if the
setValueCurveAtTimeis being processed whencancelScheduledValuesis called and the setValueCurve event is removed. What is the param value then? Same question forsetTargetAtTime.rtoy commentedon Oct 10, 2019
Teleconf: @rtoy to come up with a proposal on how this works. Probably will remove the setCurve if the cancel time lies between the start and duration of the setCurve. Not a problem for setTarget where you can always schedule something after a setTarget.
rtoy commentedon Oct 30, 2019
I think we need to consider what it means to be an "active automation".
My interpretation is that at the time
cancelScheduledValuesis called the automation is running, and we're canceling events that includes the the currently running event. Something like the following (that can be run using https://hoch.github.io/canopy):At time 0.3, we call
cancelScheduledValues(0.4)and the resultingcurve stops increasing and holds at the value it had at time 0.3.
But if we changed the example to
the output is a constant 1 up to time 0.5 and then becomes a constant 0.
For
setValueCurve, I think it might be best ifcancelScheduledValuesis called before the start of thesetValueCurve, and if the cancel time is in the middle of thesetValueCurve, the entire curve event is removed.If
cancelScheduledValuesis called when the curve is running, and the cancel time is in the middle of the curve, maybe the right thing would be to remove the curve event, and then replace it with asetValueAtTimeevent whose value is equal to the curve output at the cancel time. This is a bit complicated, but kind of matches how the linearRamp example above works.rtoy commentedon Dec 6, 2019
The behavior in the first snippet from #2071 (comment) isn't specified any where that I can find. I don't want to specify that now, so I'm not going to add anything about that for
setValueCurve.But I will make it explicit that if the cancel time is in the middle of the curve, the entire curve event is removed.
Fix WebAudio#2071: cancelScheduledValues with setValueCurveAtTime
Fix WebAudio#2071: cancelScheduledValues with setValueCurveAtTime (We…