Search code examples
javascripthtmlaudio

how to change volume on the left/right side of a audio JavaScript?


how to make onclick the sound start only on a side of the earphones

like for example right or left.

something like this: https://www.onlinemictest.com/sound-test/

so if it plays the sound on the left it, the right earphone doesn't need to make any sound.


I think it can be done by using volumes or something like that. how to do that?

(I can't edit the sound in a video editor, I want it will automatically done by javascript)

function playSound(options) {
  const choosedDirection = () => {
    return Object.keys(options)
      .reverse()
      .find(
        (direction) => direction === "left" || direction === "right",
      );
  };

  const audio = new Audio("audio.mp3");

  switch (choosedDirection()) {
    case "left":
      audio.play();
      // how to make here play only on the left side
      // by making the volume high on the left and 0 on the right
      break;
    case "right":
      audio.play();
      // how to make here play only on the right side
      // by making the volume high on the right and 0 on the left
      break;
  }
}
<head>
  <script src="https://cdn.tailwindcss.com/"></script>
</head>

<body class="h-screen grid place-items-center bg-gray-200 overflow-hidden">
  <div class="flex gap-[5vmin]">
    <div class="flex gap-[5vmin]">
    <!-- left -->
      <button title="🎶 Left sound" class="transition hover:-translate-y-1 hover:shadow-2xl focus:rotate-3 hover:border-blue-200 hover:shadow-blue-200 focus:border-blue-500 focus:shadow-blue-500 border-4 border-blue-50 shadow-md p-[10vmin] bg-white rounded-[3vmin] text-[10vmin] text-blue-500 after:content-[attr(title)] relative after:absolute after:text-sm after:-bottom-20 after:left-0 after:w-max after:bg-white after:shadow-lg after:-translate-x-[50%] after:left-[50%] after:px-4 after:py-2 after:rounded-lg after:opacity-0 focus:after:opacity-100 focus:after:duration-500 after:translate-y-12 focus:after:translate-y-0 focus:after:animate-pulse focus:animate-bounce"
        onclick="playSound({left:true})">
        🡰
      </button>
      
      <!-- right -->
      <button title="🎶 Right sound" class="transition hover:-translate-y-1 hover:shadow-2xl focus:rotate-3 hover:border-blue-200 hover:shadow-blue-200 focus:border-blue-500 focus:shadow-blue-500 border-4 border-blue-50 shadow-md p-[10vmin] bg-white rounded-[3vmin] text-[10vmin] text-blue-500 after:content-[attr(title)] relative after:absolute after:text-sm after:-bottom-20 after:left-0 after:w-max after:bg-white after:shadow-lg after:-translate-x-[50%] after:left-[50%] after:px-4 after:py-2 after:rounded-lg after:opacity-0 focus:after:opacity-100 focus:after:duration-500 after:translate-y-12 focus:after:translate-y-0 focus:after:animate-pulse focus:animate-bounce"
        onclick="playSound({right:true})">
        🡲
      </button>
    </div>

    <script>
      console.clear(); // not important, just to delete the tailwind warning of using CDN instead of NPM package
    </script>
</body>


Solution

  • You can use this solution:

    const audioUrl = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/858/outfoxing.mp3";
    const audioElement = new Audio(audioUrl);
    audioElement.crossOrigin = "anonymous";
    
    const audioContext = new AudioContext();
    
    const audioSource = audioContext.createMediaElementSource(audioElement);
    
    const volumeNodeL = new GainNode(audioContext);
    const volumeNodeR = new GainNode(audioContext);
    
    volumeNodeL.gain.value = 2;
    volumeNodeR.gain.value = 2;
    
    const channelsCount = 2;
    
    const splitterNode = new ChannelSplitterNode(audioContext, {
      numberOfOutputs: channelsCount
    });
    const mergerNode = new ChannelMergerNode(audioContext, {
      numberOfInputs: channelsCount
    });
    
    audioSource.connect(splitterNode);
    
    splitterNode.connect(volumeNodeL, 0);
    splitterNode.connect(volumeNodeR, 1);
    
    volumeNodeL.connect(mergerNode, 0, 0);
    volumeNodeR.connect(mergerNode, 0, 1);
    
    mergerNode.connect(audioContext.destination);
    
    let isPlaying;
    
    function playPause() {
      if (audioContext.state === 'suspended') {
        audioContext.resume();
      }
    
      isPlaying = !isPlaying;
      if (isPlaying) {
        audioElement.play();
      } else {
        audioElement.pause();
      }
    }
    
    function setBalance(val) {
      volumeNodeL.gain.value = 1 - val;
      volumeNodeR.gain.value = 1 + val;
    }
    <h3>Check if your speakers are connected and working with this test.</h3>
    
    <button onclick="playPause()">Play/Pause</button>
    <br><br>
    <button onclick="setBalance(-1)">🎶 Left</button>
    <button onclick="setBalance(0)">🎶 Center</button>
    <button onclick="setBalance(+1)">🎶 Right</button>