Fade auio

PHOTO EMBED

Thu Mar 17 2022 09:02:08 GMT+0000 (UTC)

Saved by @minhhung1106 #html

import React, { useCallback, useEffect, useRef, useState } from 'react';

import useEventListener from './useEventListener';

interface UseFadeAudioProps {
  audioRef: React.RefObject<HTMLAudioElement>;
  cloneAudioRef: React.RefObject<HTMLAudioElement>;
  startFade: boolean;
  paused: boolean;
}

const TIMING = 10;

const useFadeAudio = ({ audioRef, cloneAudioRef, startFade, paused }: UseFadeAudioProps) => {
  const [isStartFadeClone, setIsStartFadeClone] = useState<boolean>(false);

  const currentTimeRef = useRef<number>(0);
  const cloneCurrentTimeRef = useRef<number>(0);
  const timerIdRef = useRef<number>(0);
  const cloneTimerIdRef = useRef<number>(0);

  const canStartAudio1Ref = useRef<boolean>(true);
  const canStartAudio2Ref = useRef<boolean>(true);

  const fadeAudio = useCallback(
    (
      audio: HTMLAudioElement,
      nextAudio: HTMLAudioElement,
      isCloneAudio: boolean,
      canStartCurrentAudioRef: React.MutableRefObject<boolean>,
      canStartNextAudioRef: React.MutableRefObject<boolean>,
    ) => {
      const { duration } = audio;
      const startPoint = 50;
      const startRange = (duration * startPoint) / 100; // ex: duration = 10s, startPoint = 50% => startRange = 5s
      const fadeStart = (startRange * 1000) / TIMING;

      const timerId = window.setInterval(() => {
        const currentTime = !isCloneAudio ? currentTimeRef.current : cloneCurrentTimeRef.current;

        // Start fade in for next audio
        if (duration - currentTime <= startRange && canStartCurrentAudioRef.current) {
          nextAudio.volume = 0;
          nextAudio.play();
          cloneCurrentTimeRef.current = 0;
          canStartCurrentAudioRef.current = !canStartCurrentAudioRef.current; // Prevent
          canStartNextAudioRef.current = true;

          if (!isCloneAudio) setIsStartFadeClone(true);
        }

        // Fade in
        if (audio.volume < 1 && duration - currentTime > startRange) {
          const newVolume = audio.volume + 1 / fadeStart;

          console.log('FADE In');

          if (newVolume >= 1) audio.volume = 1;
          else audio.volume = newVolume;

          return;
        }

        // Fade out
        if (audio.volume > 0 && duration - currentTime <= startRange) {
          const newVolume = audio.volume - 1 / fadeStart;

          if (newVolume <= 0) audio.volume = 0;
          else audio.volume = newVolume;
        }

        console.log('PAUSED', timerId);
      }, TIMING);

      return timerId;
    },
    [],
  );

  useEffect(() => {
    if (paused) {
      clearInterval(timerIdRef.current);
      clearInterval(cloneTimerIdRef.current);
    }
  }, [paused]);

  useEffect(() => {
    const audio = audioRef.current;
    const nextAudio = cloneAudioRef.current;

    if (!audio || !nextAudio || !startFade) return;

    timerIdRef.current = fadeAudio(audio, nextAudio, false, canStartAudio2Ref, canStartAudio1Ref);

    return () => clearInterval(timerIdRef.current);
  }, [audioRef, cloneAudioRef, startFade, paused, fadeAudio]);

  useEffect(() => {
    const audio = cloneAudioRef.current;
    const nextAudio = audioRef.current;

    if (!audio || !nextAudio || !isStartFadeClone) return;

    cloneTimerIdRef.current = fadeAudio(
      audio,
      nextAudio,
      true,
      canStartAudio1Ref,
      canStartAudio2Ref,
    );

    return () => clearInterval(cloneTimerIdRef.current);
  }, [audioRef, cloneAudioRef, paused, isStartFadeClone, fadeAudio]);

  useEventListener(
    'timeupdate',
    () => {
      currentTimeRef.current = audioRef.current?.currentTime ?? 0;
    },
    audioRef,
  );

  useEventListener(
    'timeupdate',
    () => {
      cloneCurrentTimeRef.current = cloneAudioRef.current?.currentTime ?? 0;
    },
    cloneAudioRef,
  );
};

export default useFadeAudio;
content_copyCOPY