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

Create and maintain end-to-end frontend tests

Learn best practices on creating frontend tests, testing on-premise apps, integrating tests into your CI/CD pipeline, and using Datadog’s testing tunnel.

Download The Guide

Top comments (0)

Postmark Image

Speedy emails, satisfied customers

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up