-
-
Notifications
You must be signed in to change notification settings - Fork 36.2k
Audio: add fadeIn & fadeOut
#32549
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
Audio: add fadeIn & fadeOut
#32549
Conversation
📦 Bundle sizeFull ESM build, minified and gzipped.
🌳 Bundle size after tree-shakingMinimal build including a renderer, camera, empty scene, and dependencies.
|
1f90da4 to
4dd5355
Compare
| * @param {number} [volumeThen=1] - The volume at the end of the fade. | ||
| * @return {Audio} A reference to this instance. | ||
| */ | ||
| fadeIn( duration, volumeNow = 0, volumeThen = 1 ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've quickly checked Unreal and they also have fadein/fadeout in their Blueprint API:
https://dev.epicgames.com/documentation/en-us/unreal-engine/BlueprintAPI/Audio/Components/Audio/FadeIn
https://dev.epicgames.com/documentation/en-us/unreal-engine/BlueprintAPI/Audio/Components/Audio/FadeOut
When checking our own methods, I think fadeIn() and fadeOut() should have an optional delay parameter similar to play() and stop(). It's in seconds and you add it currentTime when scheduling the values. New singnature:
fadeIn( duration, volumeNow = 0, volumeThen = 1, delay = 0 ) {Also, do we need volumeNow? Can't we just use the current volume like in fadeOut(). It seems the Unreal component also just allows to define the target volume.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I think we can set the volumeNow beforehand
audio.setVolume(0.1);
audio.fadeIn(3, 0.5);
although there might be some issues because setVolume does not set the volume immediately.
it is using the same setTargetAtTime API with a small 0.01 timeConstant.
so it could be setVolume will be canceled by fadeIn
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about we save the value passed to setVolume() is a private variable an use it in the fade methods? In this way, the value set via setVolume() isn't lost when fading in an audio like in https://github.com/mrdoob/three.js/pull/32549/files#r2622754999. The implementation would use:
return this._scheduleFading( duration, this._volume, volumeThen );There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will check if it works fine or not with the above example
it was just a hypothesis
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found this old issue #12510
do you remember why setTargetAtTime was used and not setValueAtTime ?
- if possible I would replace it with
setValueAtTime(instant volume update) - your suggestion with
this._volume - this is evil but
currentTime + 0.01 * 3will make suresetVolumesmoothing is complete
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we care about cases when people access audio.gain.gain.value directly?
because in this scenario this._volume will not be set
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not ideal that gain is public but in general we expect developers work with setVolume().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
audio.setVolume(0.1);
audio.fadeIn(3, 0.5);
I've tested the code today an realized the usage of setTargetAtTime() in setVolume() does not work with the new fading methods. In the above code example, when fadeIn() is executed, the current volume is not set to 0.1 yet which means the interpolation to the target value won't work. After some testing this can only be fixed by using setValueAtTime() in setVolume(). Or by using your original implementation. However, I'm not a fan of setting the current volume in the fade methods since we already have setVolume() for that.
So I think before we can make this change, we have to migrate from setTargetAtTime() to setValueAtTime(). But that requires good testing and some research in older issues since setTargetAtTime() was chosen on purpose, see https://github.com/mrdoob/three.js/pull/32549/files#r2631137839.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After some more reading I'm not feeling comfortable to make the change from setTargetAtTime() to setValueAtTime(). As explained in WebAudio/web-audio-api#76 (comment), setTargetAtTime() provides a De-zippering behavior:
De-zippering is the process of smoothly approaching a target value instead of jumping to it directly. The intention is to prevent audio "glitches" which might occur if the value is changed suddenly.
setValueAtTime() does not:
If a developer explicitly sets values (using setValueAtTime for example) then de-zippering is not performed.
So if we use setValueAtTime(), we risk to introduce (platform specific) audio regressions e.g. when changing the volume. Bugs like crackling sounds were reported in the past (I actually heard them myself) and we don't experience them since we use setTargetAtTime().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After reconsideration it's probably better to close the PR and let fadein/fadeouts be implemented on application level. _scheduleFading() depends on setValueAtTime() and the consequences of using this method in audio animations are unclear.
Related issue: #32482
Description
Added audio volume fading functionality using setTargetAtTime and cancelScheduledValues.
It is also possible to use linearRampToValueAtTime or exponentialRampToValueAtTime for precise transition control, however there is limited Chrome Android / WebView support.
TODO: