DEV Community

Masui Masanori
Masui Masanori

Posted on

2

[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

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more