Gelloiss
Gelloiss

Reputation: 194

web audio api, AudioContext dont play on channel 3. Channels 4 and above do not work correctly

A 5.1 audio system is connected via hdmi. The operating system processes it correctly, I can test each individual speaker and get the expected result. enter image description here

I need to use JS to send audio to specific channels (speakers). Below is the code. The number of channels and other nuances work correctly.

  let source;
  const AudioContext = window.AudioContext || window.webkitAudioContext;
  const audioCtx = new AudioContext();

  const audioUrl = "1.mp3";
  const audioResp = await fetch(audioUrl);

  const arrayBuffer = await audioResp.arrayBuffer();
  const audioBuffer = await audioCtx.decodeAudioData(arrayBuffer);

  let channelCount = audioCtx.destination.maxChannelCount;
  let audioChannelCount = audioBuffer.numberOfChannels;

  const splitter = audioCtx.createChannelSplitter(channelCount);
  const merger = audioCtx.createChannelMerger(channelCount);

  source = audioCtx.createBufferSource();
  source.buffer = audioBuffer;
  source.connect(splitter);

  const test = splitter.connect(merger, 0, 0);
  const test2 = splitter.connect(merger, 0, 3);

  merger.connect(audioCtx.destination);

  source?.start();

If I'm writing splitter.connect(merger, 0, 0); or splitter.connect(merger, 0, 1); the audio is played correctly on the left or right speaker. But if I write splitter.connect(merger, 0, 3); it doesn't play at all. But if I specify channel 4 or 5, I get the same result as if I specify 0 or 1. All other columns are always silent. How do I get through to them? I need to be able to send a certain audio file to a certain channel.

Upvotes: 0

Views: 99

Answers (1)

Gelloiss
Gelloiss

Reputation: 194

Yes, essentially the problem is solved as follows:

const audioCtx = new AudioContext();
audioCtx.destination.channelCount = audioCtx.destination.maxChannelCount;

My final working version looks like this

const startBtn = document.getElementById('start');
  const stopBtn = document.getElementById('stop');
  const select = document.getElementById('select');

  document.addEventListener("DOMContentLoaded", async () => {
    let source;

    startBtn.addEventListener('click', async () => {
      const audioCtx = new AudioContext();
      const audioUrl = "https://www2.iis.fraunhofer.de/AAC/7.1auditionOutLeader_v2_rtb.mp4";

      const audioResp = await fetch(audioUrl);
      console.log('audioResp', audioResp);

      const arrayBuffer = await audioResp.arrayBuffer();
      console.log('arrayBuffer', arrayBuffer);

      const audioBuffer = await audioCtx.decodeAudioData(arrayBuffer);
      console.log('audioBuffer', audioBuffer);

      source = audioCtx.createBufferSource();
      source.buffer = audioBuffer;

      let channelCount = audioCtx.destination.maxChannelCount;
      let audioChannelCount = audioBuffer.numberOfChannels;

      audioCtx.destination.channelCount = channelCount; //Without this, there will only be two channels (0 and 1). The subwoofer will be silent and channels 2, 4 and above will duplicate 0 and 1.

      console.log('channelCount', channelCount);
      console.log('audioChannelCount', audioChannelCount);


      if (select.value === 'Original') {
        source.connect(audioCtx.destination);
      } else {
        const channelCountForSplitter = Math.max(channelCount, audioChannelCount);
        const splitter = audioCtx.createChannelSplitter(channelCountForSplitter);
        const merger = audioCtx.createChannelMerger(channelCountForSplitter);

        source.connect(splitter);
        for (let speakerChannel = 0; speakerChannel < channelCount; speakerChannel++) {
          for (let audioChannel = 0; audioChannel < audioChannelCount; audioChannel++) {
            splitter.connect(merger, audioChannel, speakerChannel);
          }
        }

        merger.connect(audioCtx.destination);

      }

      source?.start();

    });

    stopBtn.addEventListener('click', () => {
      source?.stop();
    });
  });
.menu {
    display: flex;
    gap: 2rem;
  }
<body>
<div class="menu">
  <select id="select">
    <option>
      Original
    </option>
    <option>
      Same on all speakers
    </option>
  </select>
  <button id="start">
    Start
  </button>
  <button id="stop">
    Stop
  </button>
</div>
</body>

Upvotes: 0

Related Questions