Realizing the effect of gradual in and out of a song playing pause — electron + Vue writing a player (1)

Time:2020-9-27

order

Decided to start blogging. Start with something simple.

Today, we are still pondering over the implementation details of music on various platforms. We find that when playing and pausing songs, they will have a short gradual in and gradual out effect. Let’s start to implement it.

Design

At present, a better way is to call the audio element’s pause interface by continuously reducing the volume to 0 in a short period of time when receiving the user‘s request for playing. When receiving the user’s pause request, the play interface of the audio element is called first, and the volume is increased to the user’s set volume in a short time

When you think about the need to go through one step in a row, two approaches come to mind,setTimeOutorsetInterValandrequestAnimationFrameBecause there is no time-consuming continuous asynchronous operation, there is no need to use thesetTimeOutTo avoidsetInterValIf there are these operations, you should avoid executing them in the main thread.

We hope that the gradual in and out of the audio can be smooth enough to avoid the grainy sound caused by the large interval of volume changesetInterValThe interval of callback execution is not fixed. It is only when the execution stack is empty that the asynchronous queue task is executed. However, there are no tasks that hinder the callback function from executingrequestAnimationFrameLet the callback function be called with the screen refresh, so that the frequency of volume change becomes fixed, and it seems to be smoother (is it really appropriate to use it for non animation rendering tasks?). On paper, you have to feel light, decide to achieve both, and then compare the effects

realization

First let’s see the difference between fade in and out and no fade in and fade out, click here to seeExamples

The following is given in therequestAnimationFrameFirst, declare the data to be used in the Vue construction option

data () {
    return {
        ...
        Volume: 1, // user set song volume
        Fadevome: 0, // the current volume of the song. Unlike volume, this variable is the real-time volume of the recorded song as it fades in and out
        Volumefadeinflag: null, // timer to save songs fade in
        Volumefadeoutflag: null, // timer to save songs fading out
        ...
    }
}

Then it increases or decreases through a cyclefadeVolumeUntil it isvolumeOr 0, for example, the fade out code is

 songVolumeFadeOut (audio) {
    this.volumeFadeInFlag && cancelAnimationFrame(this.volumeFadeInFlag)
    const _this = this;
    (function fadeOut () {
        if (_this.fadeVolume - 0.02 <= 0) {
            _this.fadeVolume = 0
            audio.volume = _this.fadeVolume
            cancelAnimationFrame(_this.volumeFadeOutFlag)
            _this.volumeFadeOutFlag = null
            audio.pause()
        } else {
            _this.fadeVolume = _this.fadeVolume - 0.02
            _this.fadeVolume = Number(_this.fadeVolume.toFixed(2))
            audio.volume = _this.fadeVolume
            _this.volumeFadeOutFlag = requestAnimationFrame(fadeOut)
        }
    })()
 }
 

Note that you need to clear the fade in loop before executing the fade out loop. If you do not, if you click the pause and play buttons, there will be multiple fades at the same time, and they can’t reach the termination condition, so they will fall into the dead loop. Because the refresh rate is about 60 times a second, and the increment is 0.02, you can end the fade in and fade out in about one second.

After writing the fade in code, it’s time to look for the execution time. I put the fade in code in theaudioelementplayEvent, so the fade in code does not need to be called manuallyaudio.play()To put the fade out on theplayingVariable, when the request of audio pause is received, fade out is executed.

onPlay() {
    ...
    //When the window is minimized or hidden, the requestanimation frame will be delayed until the window is restored, which is not what we want
    if (document.visibilityState == 'visible') {
        this.songVolumeFadeIn(audio)
    } else {
    //So we use setinterval instead of requestanimation frame when the window is not visible
        this.songVolumeFadeInByInterval(audio)
    }
    ...
}
...
watch: {
    playing() {
        ...
        if (document.visibilityState == 'visible') {
            this.songVolumeFadeOut(audio)
        } else {
            this.songVolumeFadeOutByInterval(audio)
        }
        ...
    }
}

As mentioned aboverequestAnimationFrameIs an API designed for animation

In order to improve performance and battery life, so in most browsers, whenrequestAnimationFrame()Run in Background tab or hidden<iframe>In the middle of the year,requestAnimationFrame()Will be suspended to improve performance and battery life.

If it is used in normal web pagesrequestAnimationFrameTo achieve the effect of audio fading in and out, of course, no problem (assuming that the user does not have a very fast hand speed, click the play button to instantly cut the label or minimize the browser), but in the actual desktop player, more than one main interface can control the audio playback and pause, and the mini window and tray menu can be controlled. At this time, if the main interface is minimized, it will not be carried outrequestAnimationFrameLoop, so it’s used heredocument.visibilityStateTo determine whether the main interface is visible or not, and then select whether to use itrequestAnimationFramestillsetInterval

Click here for the simple versionsource code

Recommended Today

Explain module, import and export in JavaScript

Author: Tania rascia Crazy technology house Original text:https://www.taniarascia.com/j… In the era of the Internet, websites are mainly developed with HTML and CSS. If you load JavaScript into a page, it usually provides effects and interactions in the form of small fragments. Generally, all JavaScript code is written in a file and loaded into a filescriptTag. […]