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

Note that setting AudioParam.value will be ignored when any automation events have been set on the object #128

Closed
olivierthereaux opened this issue Sep 11, 2013 · 32 comments

Comments

@olivierthereaux
Copy link
Contributor

Originally reported on W3C Bugzilla ISSUE-19765 Mon, 29 Oct 2012 23:07:00 GMT
Reported by Ehsan Akhgari [:ehsan]
Assigned to

We should note that if the author sets the value property on an AudioParam which has any automation events scheduled, the new value will be silently ignored without any exception being raised.

@olivierthereaux
Copy link
Contributor Author

Original comment by Chris Rogers on W3C Bugzilla. Tue, 13 Nov 2012 22:49:50 GMT

Fixed:
https://dvcs.w3.org/hg/audio/rev/1d8acea32c93

@olivierthereaux
Copy link
Contributor Author

Original comment by Olivier Thereaux on W3C Bugzilla. Fri, 07 Dec 2012 16:48:04 GMT

Hmm, I seem to recall a different resolution here.

http://lists.w3.org/Archives/Public/public-audio/2012JulSep/0632.html
“Setting audioparam value while there is an automation curve will cancel that automation curve and set value immediately”

Was there another discussion resulting in a different resolution, or am I mixing things up?

@olivierthereaux
Copy link
Contributor Author

Original comment by Chris Rogers on W3C Bugzilla. Fri, 07 Dec 2012 19:43:09 GMT

Thanks Olivier, you're right...

@olivierthereaux
Copy link
Contributor Author

Original comment by Ehsan Akhgari [:ehsan] on W3C Bugzilla. Tue, 11 Dec 2012 22:46:42 GMT

Hmm, the semantics of AudioParam.value are really really broken... :(

@joeberkovitz
Copy link
Contributor

Which way should it work, and which way does it work at present in UAs?

@hoch
Copy link
Member

hoch commented Oct 22, 2014

In Chrome, setting AudioParam value with the .value setter will be ignored while the automation is in progress. You have to cancel the automation first in order to set the value with setter.

@cwilso
Copy link
Contributor

cwilso commented Oct 22, 2014

Is that true for when a setValueAtTime is scheduled in far future, or only
for ramps/curves? And setTargets have a VERY different behavior...

On Wed, Oct 22, 2014 at 10:44 AM, Hongchan Choi notifications@github.com
wrote:

In Chrome, setting AudioParam value with the .value setter will be
ignored while the automation is in progress. You have to cancel the
automation first in order to set the value with the setter.


Reply to this email directly or view it on GitHub
#128 (comment)
.

@hoch
Copy link
Member

hoch commented Oct 22, 2014

@cwilso Well, you got it right.

setValueAtTime(), linearRampToValueAtTime(), exponentialRampToValueAtTime() - all of them operates consistently. When the .value is set by setter, it changes the AudioParam value instantaneously but the automation will wipe the changes along the way. There is no audible change.

However, the behavior of .setTargetAtTime() seems to be problematic. After the setter changes value during the automation, the exponential curve starts again from THAT value. Not good...

This observation is purely from my JS testing code and I need to look into the actual implementation in Chrome to see how it is really done internally. (Again, not sure about how other browsers work.)

Just to simplify the mechanism, can we cancel the automation when the setter sets the value?

@cwilso
Copy link
Contributor

cwilso commented Oct 22, 2014

I think we need to roll this into the decision once and for all about de-zippering, and really describe how this works.

@joeberkovitz
Copy link
Contributor

Agreed — automation and de-zippering and setter interaction are all part of one issue that has been dangling for a long time.

@joeberkovitz
Copy link
Contributor

Issue #108 is also part of this nest of questions.

@rtoy
Copy link
Member

rtoy commented Mar 26, 2015

Issue #172 is related and says setting AudioParam.value effectively cancels the automation and sets the value.

@notthetup
Copy link
Contributor

The other related issue here (maybe this should be a separate issue) is the getter for AudioParam.value outputs the last stable? (from setter or from setValueAtTime) value. Should this be specified in the spec?

@adelespinasse
Copy link

I still don't understand why param.value = x isn't equivalent to param.setValueAtTime(x, context.currentTime). The difference causes a lot of confusion. I suspect the reason is "it's too late, changing it now would break code". But it sounds like the semantics aren't really that well defined, so maybe it's not too late.

@joeberkovitz
Copy link
Contributor

The reason is that param.value = x causes de-zippering to take effect, an implicit ramping of the value to avoid glitches (see #76). setValueAtTime(), on the other hand, does exactly what you ask it to do.

@adelespinasse
Copy link

Oh yeah, I wasn't thinking about dezippering. But that seems like a separate issue from how the value setter interacts with automation methods. You could instead say that param.value = x is equivalent to param.setValueAtTime(param.value, context.currentTime); param.linearRampToValueAtTime(x, context.currentTime + 0.02), or however you want to specify the dezippering. At least that way you wouldn't get very nonintuitive behavior when you mix setter calls with automation. It might be a nice, concise way to specify how dezippering works, too.

@joeberkovitz
Copy link
Contributor

@adelespinasse Yup, I think that this is buried in the details of #76 and dezippering is essentially, as you say, an alias to calling a pair of primitive ramp automation methods. So the interaction between dezippering and automation is really just the interaction between, um, automation and automation.

@hoch
Copy link
Member

hoch commented Apr 9, 2015

@adelespinasse To be precise, there are some differences in using the setter and a chain of automation methods.

The setter does not rely on currentTime value at all. It just happens at the beginning of the next (if possible) rendering quantum. Also it is not a linear ramp. In that sense, the closest one to the current setter's behavior is setTargetAtTime() method.

Raymond and I talked about the possibility of replacing the setter with setTargetAtTime() internally, but this will impose some overheads to the sample rendering: although the setter guarantees the sample-accurate smoothing over time, it does not require another sample array to do the smoothing. Instead, it just uses a smoothing constant (or coefficient). On the other hand, any AudioParam automation needs an extra array for smoothed parameter values that matches the render block input array sample by sample.

Back to the original question:

I still don't understand why param.value = x isn't equivalent to param.setValueAtTime(x, context.currentTime).

In my opinion, the setter is designed to be abused when the strongly-timed transition is not needed. It is relatively cheap and easy to use. The unfortunate thing to know is once you use the automation method, there is no going back. (the setter won't work) It might matter when the client has low memory or processing power.

@rtoy
Copy link
Member

rtoy commented Apr 9, 2015

On Thu, Apr 9, 2015 at 1:35 PM, Hongchan Choi notifications@github.com
wrote:

@adelespinasse https://github.com/adelespinasse To be precise, there
are some differences in using the setter and a chain of automation methods.

The setter does not rely on currentTime value at all. It just happens at
the beginning of the next (if possible) rendering quantum. Also it is not a
linear ramp. In that sense, the closest one to the current setter's
behavior is setTargetAtTime() method.

Raymond and I talked about the possibility of replacing the setter with
setTargetAtTime() internally, but this will impose some overheads to the
sample rendering: although the setter guarantees the sample-accurate
smoothing over time, it does not require another sample array to do the
smoothing. Instead, it just uses a smoothing constant (or coefficient). On
the other hand, any AudioParam automatio
​n​needs an extra array for smoothed parameter values that matches the
render block input array sample by sample.

​I think this is an implementation detail of Chrome. Currently, Chrome
would need a (small 128 element) array to do the smoothing.

I think Hongchan and I agreed that this has a certain appeal to make
everything uniform and relatively easy to explain. But it would also
require further changes since there is now no longer an "intrinsic" value
for the getter to return. There are probably also some corner cases that
we need to think about.​

Back to the original question:

I still don't understand why param.value = x isn't equivalent to
param.setValueAtTime(x, context.currentTime).

In my opinion, the setter is designed to be abused when the strongly-timed
transition is not needed. It is relatively cheap and easy to use. The
unfortunate thing to know is once you use the automation method, there is
no going back. (the setter won't work) It might matter when the client has
low memory or processing power.


Reply to this email directly or view it on GitHub
#128 (comment)
.

Ray

@joeberkovitz
Copy link
Contributor

It sounds like my earlier comment about dezippering mapping to internal automation calls may have been inaccurate. But if there is a way to make such a mapping official, it would be simpler and more economical. I think that the question of what internal state the getter returns can be layered on top of this mapping.

@notthetup
Copy link
Contributor

Another idea to throw into this discussion:

The setter could be defined to specifically cancel all automation when it's called. So using the setter basically says "I want to set the the value to X (with dezippering?), and that over-rules everything else I said earlier".

That way just as it's easy to switch into the automation mode (by calling any of the automation methods) it would be easy to switch out of automation.

@rtoy
Copy link
Member

rtoy commented Apr 10, 2015

Why not just use cancelScheduledValues()? At least on chrome, that seems
to allow the setter (and getter) to work again. And it seems to cause the
getter value to be set to the value at the time of cancellation.

On Thu, Apr 9, 2015 at 5:28 PM, Chinmay Pendharkar <notifications@github.com

wrote:

Another idea to throw into this discussion:

The setter could be defined to specifically cancel all automation when
it's called. So using the setter basically says "I want to set the the
value to X (with dezippering?), and that over-rules everything else I said
earlier".

That way just as it's easy to switch into the automation mode (by calling
any of the automation methods) it would be easy to switch out of automation.


Reply to this email directly or view it on GitHub
#128 (comment)
.

Ray

@rtoy
Copy link
Member

rtoy commented Apr 10, 2015

My mistake. cancelScheduledValues() doesn't allow the getter/setter to
work again. setTargetAtTime seems to allow the getter and setter to work,
but the other automation methods appear not to.

On Thu, Apr 9, 2015 at 5:41 PM, Raymond Toy toy.raymond@gmail.com wrote:

Why not just use cancelScheduledValues()? At least on chrome, that seems
to allow the setter (and getter) to work again. And it seems to cause the
getter value to be set to the value at the time of cancellation.

On Thu, Apr 9, 2015 at 5:28 PM, Chinmay Pendharkar <
notifications@github.com> wrote:

Another idea to throw into this discussion:

The setter could be defined to specifically cancel all automation when
it's called. So using the setter basically says "I want to set the the
value to X (with dezippering?), and that over-rules everything else I said
earlier".

That way just as it's easy to switch into the automation mode (by calling
any of the automation methods) it would be easy to switch out of automation.


Reply to this email directly or view it on GitHub
#128 (comment)
.

Ray

Ray

@notthetup
Copy link
Contributor

Yup. It's some sort of "last stable" value.

@hoch
Copy link
Member

hoch commented Apr 10, 2015

@notthetup Yes, that was the one of ideas. I think this is reasonable thing and a useful escape hatch.

"I want to set the the value to X (with dezippering?), and that over-rules everything else I said earlier".

However, what if the setter was triggered at x second and the scheduler has some value scheduled later than x? Also we have to consider that the timing x second will not be sample-accurate. So basically it is about deleting sample-accurate scheduled values with a non-sample-accurate manner.

I like this idea but its flakiness slightly bothers me.

@notthetup
Copy link
Contributor

Yup. Makes sense. This is something that will be hard to pin down when going from the sample-accurate (automation) 'mode' into the non-sample-accurate (non-automation) 'mode'. Both with setters and getters.

@joeberkovitz
Copy link
Contributor

Can't help but think this would be simpler if someone could propose a way to determine -- with sample accuracy -- the exact block-boundary time at which a setter-caused value change would take place.

I also think it makes sense to consider allowing cancelScheduledValues() to restore the getter/setter action.

@cwilso
Copy link
Contributor

cwilso commented Apr 13, 2015

Isn't currentTime an accurate determination of that? It represents the beginning of the next sample block.

@mark-buer
Copy link
Contributor

Audio-time marches on :) Perhaps mid-way through a JS calculation.

Waiting for a render doesn't offer much help either:

var t = ac.currentTime;
while (t === ac.currentTime) {
    // wait for the next render
}
// now do stuff that is time dependent that we wish to be applied within a single known render quanta
// (lets just hope that a GC doesn't thwart our plans)

(I'm not suggesting that anyone actually uses this)

In the spec, currentTime doesn't seem very well defined.
Does the implementation increment currentTime before or after a rendering quanta?
Rendering a quanta within the audio thread takes a non-zero amount of time, and the audio nodes are traversed in an undefined order. Thus, if currentTime is updated "before", it is possible that the above code snippet could actually make the application of param values less predictable.

@joeberkovitz
Copy link
Contributor

See #381... agreement on the definition not so simple apparently.

@joeberkovitz
Copy link
Contributor

Resolution: state that setting the .value attribute is equivalent to 1) calling setValueAtTime(context.currentTime, value) and 2) setting the internal cached intrinsic value that will be returned by the .value getter. There is no cancellation of any existing automation events.

@joeberkovitz
Copy link
Contributor

@cwilso and @rtoy and @hoch said they have some other proposal on this resolution; need to discuss.

joeberkovitz added a commit that referenced this issue Sep 24, 2015
Fix #128: clarify effect of setting the value attribute with respect …
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

9 participants