DEV Community

Masui Masanori
Masui Masanori

Posted on

[TypeScript] Play my own voice

Intro

This time, I play my own voice with Web Audio API.

Environments

  • Node.js ver.16.7.0
  • TypeScript ver.4.3.5
  • Webpack ver.5.42.0
  • ts-loader ver.9.2.3",
  • webpack-cli ver.4.7.2

Basic usage

To control the audio data, first create an "AudioContext".
Each operation such as audio setting and volume up / down is expressed as "AudioNode".

From input to output, I connect all the "AudioNode".
Alt Text

Use mic

This time, I use microphone.
To do this, I get devices with "getUserMedia".

main.page.ts

export async function init(): Promise<void> {
    // Get audio(microphone)
    const medias = await navigator.mediaDevices.getUserMedia({
        video: false,
        audio: true,
    });
    const audioContext = new AudioContext();
    const audioSourceNode = audioContext.createMediaStreamSource(medias);
    // By default, use speaker of the computer as output
    audioSourceNode
        .connect(audioContext.destination);
}
Enter fullscreen mode Exit fullscreen mode

Add effects

I can connect effects.

main.page.ts

export async function init(): Promise<void> {
...
    audioContext = new AudioContext();
    const audioSourceNode = audioContext.createMediaStreamSource(medias);

    // volume up    
    const gain = audioContext.createGain();
    gain.gain.value = 2.0;
    // delay the sound
    const delay = new DelayNode(audioContext);
    delay.delayTime.value = 1;
    // output only right channel
    const panner = new StereoPannerNode(audioContext, { pan: 1 });

    audioSourceNode
        .connect(gain)
        .connect(delay)
        .connect(panner)
        .connect(audioContext.destination);
}
Enter fullscreen mode Exit fullscreen mode

gain

Alt Text

delay

Alt Text

panner

Alt Text

Update effect values

After connecting, I can update the effect's values.

Next time, I will try more effects.

Split and merge channels

Split channels

I can split channels to left and right with "createChannelSplitter".

main.page.ts

export async function init(): Promise<void> {
...
    // volume up    
    const gain = audioContext.createGain();
    gain.gain.value = 2.0;
    // delay the sound
    const delay = new DelayNode(audioContext);
    delay.delayTime.value = 1;
    // output only right channel
    const panner = new StereoPannerNode(audioContext, { pan: 1});

    const splitter = audioContext.createChannelSplitter(2);
    audioSourceNode.connect(splitter);
    splitter.connect(gain, 1);
    splitter.connect(delay, 1);
    // No any effects...
    splitter.connect(panner, 1);
    splitter.connect(audioContext.destination);
}
Enter fullscreen mode Exit fullscreen mode

Alt Text

Because the audio source becomes mono by "ChannelSplitterNode", I can't pan again.
So "StereoPannerNode" in the sample code doesn't work.

Merge sources

After splitting, I can merge them with "ChannelMergerNode".

main.page.ts

export async function init(): Promise<void> {
...
    // volume up    
    const gain = audioContext.createGain();
    gain.gain.value = 2.0;
    // delay the sound
    const delay = new DelayNode(audioContext);
    delay.delayTime.value = 0.1;

    const splitter = audioContext.createChannelSplitter(2);
    audioSourceNode.connect(splitter);
    splitter.connect(gain, 1);
    splitter.connect(delay, 1);

    const merger = audioContext.createChannelMerger(2);
    gain.connect(merger, 0, 1);
    delay.connect(merger, 0, 1);
    splitter.connect(merger, 1, 0);
    merger.connect(audioContext.destination);
}
Enter fullscreen mode Exit fullscreen mode

Alt Text

Resources

Discussion (0)