Reputation: 194
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.
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
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