Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web audio 5.1 (6 channel) output

I am trying to route stereo audio through a channelsplitter to 6 channels with gain controls, and then back into a channelMerger, to control all 6 channels of a 5.1 set. The set is connected through HDMI, and windows outputs to all 6 channels correctly (a screen where you can let all 6 speakers play a sound separately).

The only examples I could find have this piece of code:

if (context.destination.maxChannelCount >= 6) {
    context.destination.channelCount = 6;
}
else {
    context.destination.channelCount = 2;
}

When initialising the audiocontext, my channelCount defaults to 2 and the maxChannelCount is 6.

I use the following code to create the splitter, merger and gains inbetween:

if (context.destination.maxChannelCount >= 6) {
    context.destination.channelCount = 6;
}
else {
    context.destination.channelCount = 2;
}

context.destination.channelCountMode = "explicit";
context.destination.channelInterpretation = "discrete";

var ammount = context.destination.channelCount;

console.log('Ammount of channels:',ammount); //this outputs 6

window.channelSplitter = context.createChannelSplitter(ammount);
window.channelMerger = context.createChannelMerger(ammount);

postGain.connect(channelSplitter); //postGain is the last node of the audio system
channelMerger.connect(context.destination);
window.channelGains = [];
for(i=0;i<ammount;i++){
    channelGains[i] = context.createGain();

    channelSplitter.connect(channelGains[i],i,0);
    channelGains[i].connect(channelMerger,0,i);
}

I have tried this in chrome(39.0.2171.71 m), where maxChannelCount is 6. Firefox outputs 2.

Edit: After fiddling with the channelSplitter, I found out that all outputs besides the first two are left silent. That is correct according to the spec, when using channelinterpretation 'speakers'. This would mean that I need to fill the channels myself, probably by using the algorithms described here.I still have to check if chrome outputs all 6 channels correctly.

like image 598
MarijnS95 Avatar asked Nov 28 '14 18:11

MarijnS95


1 Answers

The problem was caused by the channelSplitter not outputting on all channels (which I expected). Although this behavior is correct according to the spec. Thus we need to write our own stereo to 5.1 upmixer. But for testing sound output I used the left channel, and I was able to output to all 6 channels independently. I only encountered one problem. The input parameter (3rd one) on the connect method does not determine the order of the output, like seen here. The order of calling .connect() determines the order of the output. However, the 3rd number needs to be present and different from the other times I called .connect (but within the bounds of ammount of inputs).

Another thing I noticed that the channelCount on the merger and splitter equals to 2. However I found that it does not matter when having channelCountMode set to max

Besides all the above, I fiddled with all those settings, but they do not have any inpact on this. The only thing that is important to do is to set channelCount on the destination node to maxChannelCount.

However, when not connecting all channels to a channel merger, the merger upmixes the incoming signals according to these rules. When setting the channelInterpretation to explicit, you still get the upmixing result, whereas according to the spec it should fill the channels, and leave every channel not having an input empty (and thus only outputting the first channel to the left channel, and leave the right output silent).

Below is a snippet to fiddle with stereo channels.

onload = function(){
  window.context = new AudioContext();
  window.source = context.createMediaElementSource(document.getElementById('player'));
  window.splitter = context.createChannelSplitter(2);
  source.connect(splitter);
  window.merger = context.createChannelMerger(2);

  window.leftGain = context.createGain();
  window.rightGain = context.createGain();

  splitter.connect(leftGain, 0, 0);
  splitter.connect(rightGain, 1, 0);

  
  //--------try (de)commenting things below-------
  leftGain.connect(merger, 0, 0);
  rightGain.connect(merger, 0, 1);
  //merger.channelInterpretation = 'discrete' //doesn't seem to have influcence..
  //merger.channelCountMode = 'explicit' //makes everything only output to the left channel
  
  //-------until here------
  
  merger.connect(context.destination);

  var leftRange = document.querySelector('#left');
  var rightRange = document.querySelector('#right');
  leftRange.oninput = function(){leftGain.gain.value = this.value}
  rightRange.oninput = function(){rightGain.gain.value = this.value}
}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>JS Bin</title>
  </head>
  <body>
    <audio src="http://upload.wikimedia.org/wikipedia/en/4/45/ACDC_-_Back_In_Black-sample.ogg" controls autoplay id="player" preload></audio><br />
    <label for="left">Left channel</label>
    <input type="range" min=0 max=1 step=.01 value=1 id="left" /><br />
    <label for="right">Right channel</label>
    <input type="range" min=0 max=1 step=.01 value=1 id="right" />
  </body>
</html>
like image 174
MarijnS95 Avatar answered Oct 17 '22 01:10

MarijnS95