[TypeScript] Play my own voice
Tags: typescript, webaudioapi
Published: 2021-08-27 18:56:02

## 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fbjy1h2s7ddisary7u1h.png)

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

#### main.page.ts
```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);
}
```

### Add effects
I can connect effects.

#### main.page.ts
```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);
}
```
#### gain
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wt0u10jtkpnumjlug6il.png)

#### delay
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9ix27p65oe7q6ktana78.png)
#### panner
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u8fwbziwr8uoxrzeysk1.png)

### 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
```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);
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pcni0lmumt2o2cw7nqaw.png)

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
```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);
}
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yr51uwnsc3yflfvxrg9b.png)

## Resources
* [Web Audio API - Web API | MDN](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API)
* [MediaStream - Web API | MDN](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream)
* [ChannelMergerNode - Web API | MDN](https://developer.mozilla.org/en-US/docs/Web/API/ChannelMergerNode)
* [ChannelSplitterNode - Web API | MDN](https://developer.mozilla.org/en-US/docs/Web/API/ChannelSplitterNode)
* [DOM - BaseAudioContext.createChannelSplitter - 解決方法](https://code.i-harness.com/ja-jp/docs/dom/baseaudiocontext/createchannelsplitter)
* [ChromeでWebRTCステレオ配信 | さくらのナレッジ](https://knowledge.sakura.ad.jp/26572/)