4

I am working on a mod player which is an audio file with 4 different tracks (channels) using webaudio/audioWorkletNode.

I got it working correctly using a 2 channel (stereo) audio node:

  • channels (tracks) 0 & 3 are mixed into the left channel
  • channels (tracks) 1 & 2 are mixed into the right channel

The problem is that I'd like to analyse and show a waveform display for each of the tracks (so there should be 4 different analysers).

I had the idea of creating an audioWorkletNode with outputChannelCount set to [4], connect an analyser to each of the node's four channels, and then use a channelMerger to mix it into 2 stereo channels.

So I used the following code, expecting it to create a node with 4 channels:

let node = new AudioWorkletNode(context, 'processor', { outputChannelCount: [4] });

But the outputChannelCount parameter seems to be ignored. No matter what I specify, it's set to 2 channels in the end.

Is there a way to do it another way, or must I handle the analyse myself, using my own analyser?

warpdesign
  • 727
  • 2
  • 7
  • 17
  • I believe this is a bug in Chrome and also an issue with the spec. If outputChannelCount is given, it's supposed to be honored if the number of inputs and outputs are 1, as you have here. This is fixed in the spec, and Chrome canary should have this fixed. – Raymond Toy Sep 12 '18 at 16:12
  • Oh, interesting! I'll download Canary to see if it's fixed. I hope [this related bug](https://bugs.chromium.org/p/chromium/issues/detail?id=880784&q=audioworklet&colspec=ID%20Pri%20M%20Stars%20ReleaseBlock%20Component%20Status%20Owner%20Summary%20OS%20Modified) will be fixed too: it makes debugging really difficult in Chrome 69... – warpdesign Sep 13 '18 at 07:12
  • Just tested with Chrome build 71.0.3550.3 and it's not fixed: outputChannelCount still seems to be ignored. (That's on OSX) – warpdesign Sep 13 '18 at 08:01
  • Hmm. The fix landed in 71.0.3550.0, so it should be there. I recommend filing an issue at crbug.com/new with a simple example showing that it's not working. – Raymond Toy Sep 13 '18 at 15:02

1 Answers1

5

I finally found a way to mix all four channels and pass each channel to its own analyser by doing that:

this.context.audioWorklet.addModule(`js/${soundProcessor}`).then(() => 
{
    this.splitter = this.context.createChannelSplitter(4);
    // Use 4 inputs that will be used to send each track's data to a separate analyser
    // NOTE: what should we do if we support more channels (and different mod formats)?
    this.workletNode = new AudioWorkletNode(this.context, 'mod-processor', {
            outputChannelCount: [1, 1, 1, 1],
            numberOfInputs: 0,
            numberOfOutputs: 4
    });

    this.workletNode.port.onmessage = this.handleMessage.bind(this);
    this.postMessage({
        message: 'init',
        mixingRate: this.mixingRate
    });
    this.workletNode.port.start();

    // create four analysers and connect each worklet's input to one
    this.analysers = new Array();

    for (let i = 0; i < 4; ++i) {
        const analyser = this.context.createAnalyser();
        analyser.fftSize = 256;// Math.pow(2, 11);
        analyser.minDecibels = -90;
        analyser.maxDecibels = -10;
        analyser.smoothingTimeConstant = 0.65;
        this.workletNode.connect(analyser, i, 0);
        this.analysers.push(analyser);
    }

    this.merger = this.context.createChannelMerger(4);

    // merge the channel 0+3 in left channel, 1+2 in right channel
    this.workletNode.connect(this.merger, 0, 0);
    this.workletNode.connect(this.merger, 1, 1);
    this.workletNode.connect(this.merger, 2, 1);
    this.workletNode.connect(this.merger, 3, 0);
    this.merger.connect(this.context.destination);
});

I basically create a new node with 4 outputs and use the outputs as a channel. To produce a stereo output I can then use a channel merger. And voila!

Complete source code of the app can be found here: https://warpdesign.github.io/modplayer-js/

warpdesign
  • 727
  • 2
  • 7
  • 17