DEV Community

Masui Masanori
Masui Masanori

Posted on

3 1

[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.

Image of Datadog

The Future of AI, LLMs, and Observability on Google Cloud

Datadog sat down with Google’s Director of AI to discuss the current and future states of AI, ML, and LLMs on Google Cloud. Discover 7 key insights for technical leaders, covering everything from upskilling teams to observability best practices

Learn More

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs