Tonejs / Tone.js

A Web Audio framework for making interactive music in the browser.
https://tonejs.github.io
MIT License
13.41k stars 976 forks source link

Reversing outputs when using connect() not working? #961

Closed thely closed 2 years ago

thely commented 2 years ago

Describe the bug For part of my site, I have some short sound files that have a really strong L -> R movement. In some spots, I'd like to flip their pan, so that I get R -> L, which I'm trying to do simply just by flipping the outputs – L goes to R, R goes to L. Trouble is, when I attempt to reverse the outputs, I get the following error: AudioNode.connect: Input index 1 is out of bounds

Relevant code:

const file = "audio.mp3";
const player = new Tone.Player(file);
const channel = new Tone.Channel({ channelCount: 2 });

player.connect(channel);

// works fine
// channel.connect(Tone.getDestination());

// will break
channel.connect(Tone.getDestination(), 0, 1);
channel.connect(Tone.getDestination(), 1, 0);

The file I'm using is definitely stereo, and without the channel flipping it plays in stereo and without errors.

I have a feeling I may be fundamentally confusing something about the difference between numberOfInputs/Outputs and channelCount, and which one actually matters for what I'm asking connect() to do. I checked the channelCount for the player, channel, and destination, and all of them show 2. But their inputs/outputs always show 1, which I'm assuming is the number of nodes connected.

This is definitely something that's possible normally with both physical gear and DAWs, but does web audio and/or Tone not like this kind of selective re-routing? Additionally, if this is possible, is it more performant to have two separate Players, with one routed normally and one reversed, or to have one Player and just disconnect/reconnect it as needed? Or should I have two mono Players each holding one side of the stereo pair, and reroute them to different L/R sides of a Channel?

To Reproduce Here's a Codesandbox link.

Expected behavior To be able to reverse the channels (and by doing so, the pan) of a Player.

What I've tried In addition to the above, if I flip the order of the channel.connect lines, I get a DOMException with no text in Vue, but a createIndexSizeError in CodeSandbox.

tambien commented 2 years ago

Thanks for the issue, this is actually a confusing part of the Web Audio specification which Tone.js inherits from.

An input/output connection can actually carry numerous audio channels. A single connection can be between 1-32 channels. So in your case, the channel count is in fact stereo, but send through 1 connection.

A solution here is to use Tone.Split/Merge to separate the individual channels into individual outputs and then merge them back in in reverse order.

I think something like this should work:

const split = new Tone.Split(2);
const merge = new Tone.Merge(2);

split.connect(merge, 1, 0);
split.connect(merge, 0, 1);