warpdesign
warpdesign

Reputation: 747

creating an audioWorkletNode with 4 channels?

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:

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?

Upvotes: 4

Views: 1890

Answers (2)

Henri
Henri

Reputation: 11

I think it should be:

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

instead of 4, as you only use input indexes 0 and 1.

Upvotes: 1

warpdesign
warpdesign

Reputation: 747

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/

Upvotes: 5

Related Questions