DEV Community

Masui Masanori
Masui Masanori

Posted on

[TypeScript] Play my own voice 2

Intro

This time, I try "BiquadFilterNode" to control tone.

Sample code

index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>xlsx sample</title>
        <meta charset="utf-8">
    </head>
    <body>
        <div>
            <div>EQ</div>
            <select id="eq_input">
                <option>allpass</option>
                <option>bandpass</option>
                <option>highpass</option>
                <option>highshelf</option>
                <option>lowpass</option>
                <option>lowshelf</option>
                <option>notch</option>
                <option>peaking</option>
            </select>
            <div>Frequency</div>
            <select id="eq_frequency">
                <option>10</option>
                <option>100</option>
                <option>350</option>
                <option>1000</option>
                <option>5000</option>
                <option>10000</option>
                <option>22050</option>
            </select>
            <div>Gain</div>
            <select id="eq_gain">
                <option>-40</option>
                <option>-20</option>
                <option>-10</option>
                <option>0</option>
                <option>10</option>
                <option>20</option>
                <option>40</option>
            </select>
            <div>Detune</div>
            <select id="eq_detune">
                <option>0</option>
                <option>10</option>
                <option>100</option>
                <option>350</option>
                <option>1000</option>
                <option>5000</option>
                <option>10000</option>
                <option>22050</option>
            </select>
            <div>Q</div>
            <select id="eq_q">
                <option>0</option>
                <option>0.0001</option>
                <option>0.001</option>
                <option>0.01</option>
                <option>0.1</option>
                <option>1</option>
                <option>10</option>
                <option>100</option>
                <option>1000</option>
            </select>
        </div>
        <script src="./js/main.page.js"></script>
        <script>Page.init();</script>
    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

main.page.ts

let audioContext: AudioContext;

export async function init(): Promise<void> {
    const medias = await navigator.mediaDevices.getUserMedia({
        video: false,
        audio: true,
    });

    audioContext = new AudioContext();
    const audioSourceNode = audioContext.createMediaStreamSource(medias);
    const biquadFilter = audioContext.createBiquadFilter();

    audioSourceNode
        .connect(biquadFilter)
        .connect(audioContext.destination);

    const eqSelect = document.getElementById('eq_input') as HTMLSelectElement;
    eqSelect.onchange = () => {
        const eqValue = eqSelect.options[eqSelect.selectedIndex]?.text;
        if(eqValue == null) {
            return;
        }
        switch(eqValue) {
            case 'allpass':
                biquadFilter.type = 'allpass';
                break;
            case 'bandpass':
                biquadFilter.type = 'bandpass';
                break;
            case 'highpass':
                biquadFilter.type = 'highpass';
                break;
            case 'highshelf':
                biquadFilter.type = 'highshelf';
                break;
            case 'lowpass':
                biquadFilter.type = 'lowpass';
                break;
            case 'lowshelf':
                biquadFilter.type = 'lowshelf';
                break;
            case 'notch':
                biquadFilter.type = 'notch';
                break;
            case 'peaking':
                biquadFilter.type = 'peaking';
                break;
        }
    };
    const eqFrequencySelect = document.getElementById('eq_frequency') as HTMLSelectElement;
    eqFrequencySelect.onchange = () => {
        const eqFrequencyText = eqFrequencySelect.options[eqFrequencySelect.selectedIndex]?.text;
        if(eqFrequencyText == null) {
            return;
        }
        const eqFrequency = parseInt(eqFrequencyText);
        if(isNaN(eqFrequency)) {
            return;
        }
        biquadFilter.frequency.setValueAtTime(eqFrequency, audioContext.currentTime);
    };
    const eqGainSelect = document.getElementById('eq_gain') as HTMLSelectElement;
    eqGainSelect.onchange = () => {
        const eqGainText = eqGainSelect.options[eqGainSelect.selectedIndex]?.text;
        if(eqGainText == null) {
            return;
        }
        const eqGain = parseInt(eqGainText);
        if(isNaN(eqGain)) {
            return;
        }
        biquadFilter.gain.setValueAtTime(eqGain, audioContext.currentTime);
    };
    const eqDetuneSelect = document.getElementById('eq_detune') as HTMLSelectElement;
    eqDetuneSelect.onchange = () => {
        const eqDetuneText = eqDetuneSelect.options[eqDetuneSelect.selectedIndex]?.text;
        if(eqDetuneText == null) {
            return;
        }
        const eqDetune = parseInt(eqDetuneText);
        if(isNaN(eqDetune)) {
            return;
        }
        biquadFilter.detune.setValueAtTime(eqDetune, audioContext.currentTime);
    };
    const eqQSelect = document.getElementById('eq_q') as HTMLSelectElement;
    eqQSelect.onchange = () => {
        const eqQText = eqQSelect.options[eqQSelect.selectedIndex]?.text;
        if(eqQText == null) {
            return;
        }
        const eqQ = parseInt(eqQText);
        if(isNaN(eqQ)) {
            return;
        }
        biquadFilter.Q.setValueAtTime(eqQ, audioContext.currentTime);
    };
}
Enter fullscreen mode Exit fullscreen mode

type

"BiquadFilterNode" has preset filters. I can use them by "BiquadFilterNode.type".

Modify filters

I can modify the selected filter by "gain", "frequency", "detune", "Q".

gain

I can control gain of filter by "BiquadFilterNode.gain".
Only "highshelf", "lowshelf", "peaking" of "BiquadFilterNode.type" can use.
The lowest value is -40(dB) and the highest one is 40(dB).

frequency, detune

"frequency", "detune" are used to compute frequency of the filter.

computedFrequency(t) = frequency(t) * pow(2, detune(t) / 1200)
Enter fullscreen mode Exit fullscreen mode

Because some types emphasize specific frequency by default, I can't hear the sound when I set specific values into them.

type the value what I can't hear the sound
bandpass 10
highpass 22050
lowpass 10

I can't feel the differences when I change the values with "highshelf", "lowshelf", "peaking".

Q

This express Quality factor.
I haven't understood what is Quality factor.

So maybe I will wrtite more about it later.

The max value and min value are different per types.
For example, when I use "bandpass" and set Q value as 100, I can't hear the sound.
When I use "highpass" and set Q value as 100, I hear some noize like howling.

Discussion (0)