Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTML5 <audio> playback with fade in and fade out

I'd like to start and stop HTML5 playback in a random position with fade in and fade out periods to smooth the listening experience.

What kind of mechanisms exists for this? Manually ramp up the volume with setTimeout()?

like image 450
Mikko Ohtamaa Avatar asked Sep 17 '11 00:09

Mikko Ohtamaa


People also ask

What does fade-in and fade-out mean in audio?

Fade In (1) begins with silence and gradually becomes louder until full volume. Fade Out (2) makes audio progressively softer until it can no longer be heard.


2 Answers

The jQuery way...

$audio.animate({volume: newVolume}, 1000); 

Edit: where $audio is a jQuery-wrapped audio element and newVolume is a double between 0 and 1.

Edit: The element's effective media volume is volume, interpreted relative to the range 0.0 to 1.0, with 0.0 being silent, and 1.0 being the loudest setting, values in between increasing in loudness. The range need not be linear. http://www.w3.org/html/wg/drafts/html/master/embedded-content.html#effective-media-volume

Edit: People are posting vanilla JavaScript implementations, so I'll post a vanilla TypeScript one that preserves the jQuery swing animation (just strip out the type info if you want to run this in JavaScript). Disclaimer, this is completely untested:

export async function adjustVolume(     element: HTMLMediaElement,     newVolume: number,     {         duration = 1000,         easing = swing,         interval = 13,     }: {         duration?: number,         easing?: typeof swing,         interval?: number,     } = {}, ): Promise<void> {     const originalVolume = element.volume;     const delta = newVolume - originalVolume;      if (!delta || !duration || !easing || !interval) {         element.volume = newVolume;         return Promise.resolve();     }      const ticks = Math.floor(duration / interval);     let tick = 1;      return new Promise(resolve => {         const timer = setInterval(() => {             element.volume = originalVolume + (                 easing(tick / ticks) * delta             );              if (++tick === ticks + 1) {                 clearInterval(timer);                 resolve();             }         }, interval);     }); }  export function swing(p: number) {     return 0.5 - Math.cos(p * Math.PI) / 2; } 
like image 103
jedmao Avatar answered Sep 25 '22 02:09

jedmao


Old question but if anyone is looking for a vanilla JS way to do this I just wrote something up for project and thought I'd post it here since my search for a solution was in vain. If you are already working with a video or audio element, there's a good chance you don't really need to use jQuery to control the object anyways.

function getSoundAndFadeAudio (audiosnippetId) {      var sound = document.getElementById(audiosnippetId);      // Set the point in playback that fadeout begins. This is for a 2 second fade out.     var fadePoint = sound.duration - 2;       var fadeAudio = setInterval(function () {          // Only fade if past the fade out point or not at zero already         if ((sound.currentTime >= fadePoint) && (sound.volume != 0.0)) {             sound.volume -= 0.1;         }         // When volume at zero stop all the intervalling         if (sound.volume === 0.0) {             clearInterval(fadeAudio);         }     }, 200);  } 

This version doesn't allow for editing the fadeout time (set to 2 seconds) but you could pretty easily argumentize it. To fully generisize this, extra logic would be needed to also first check what the volume was set to in order to know the factor by which to fade it out. In our case, we preset the volume to 1 already and browser volume control is out of the users hands as it's for a slideshow thing so it wasn't needed.

To get to a specific part of the audio you'd want to check the seekable timerange and just set the currentTime randomly based on what's available.

like image 25
user801985 Avatar answered Sep 22 '22 02:09

user801985