Rivka
Rivka

Reputation: 171

Web audio API ChannelMergerNode not working as expected on Safari

I've created a simple jsfiddle using ChannelMergerNode, to play oscillator on the right speaker. It works as expected on Chrome, but on Safari the sound plays to both speakers (right and left).

var audioContext = window.AudioContext || window.webkitAudioContext;
var context = new audioContext();
var merger = context.createChannelMerger();
merger.connect(context.destination);
var osc = context.createOscillator();
osc.connect(merger, 0, 1);
osc.start();
osc.stop(10.0);

https://jsfiddle.net/RivkaB/tcnofjy1/16/

Any idea how solve this issue? Thank you.

Upvotes: 0

Views: 427

Answers (2)

Raymond Toy
Raymond Toy

Reputation: 6048

I think Safari hasn't updated its ChannelMergerNode to follow the spec. It's been a while, but I think what's happening is that since you only connect one input, the output contains just the one channel, basically ignoring the unconnected input 0.

If you want this to work with Safari, you need to connect something to input 0. This could be your oscillator connected to a zero-gain node. Or maybe a looping AudioBufferSourceNode with a buffer of all zeros.

But I'm not 100% sure this will work either. If this doesn't work, use AudioBufferSourceNode with a very very tiny value, like 1e-20.

Upvotes: 0

Emiel Zuurbier
Emiel Zuurbier

Reputation: 20934

The ChannelMergerNode interface is used to merge channels that have been split-up by a ChannelSplitterNode into a single channel. The panning effect that you get might be a side effect of the Chrome implementation of that node, although I'm not sure.

If you wan't to create a stereo panning effect then create a StereoPannerNode which allows you to control the output on the left and right side.

The StereoPannerNode has a pan property. This property has a value property which can be a number ranging from -1 (left) to 1 (right), with 0 being the center.

const buttons = document.querySelectorAll('button');

const audioContext = new AudioContext();
const stereoPannerNode = audioContext.createStereoPanner();
const oscillatorNode = audioContext.createOscillator();
  
oscillatorNode.connect(stereoPannerNode);
stereoPannerNode.connect(audioContext.destination);

for (const button of buttons) {
  button.addEventListener('click', function() {
    if (button.value === 'play') {
      oscillatorNode.start();
    } else if (button.value === 'left') {
      stereoPannerNode.pan.value = -1;
    } else if (button.value === 'right') {
      stereoPannerNode.pan.value = 1;
    } else {
      stereoPannerNode.pan.value = 0;
    }
  });
}
<button value="play">Play</button>
<button value="left">Only left</button>
<button value="right">Only right</button>
<button value="both">Both</button>

Upvotes: 1

Related Questions