WebAudioAPI 사용

이 글의 내용


다음은 간단한 모바일 해설을 통해 브라우저에서 사운드를 사용하는 API 웹오디오 API에 대한 해설입니다.
우선 분위기와 흐름을 파악하도록 이 글을 썼습니다.
글에는 MDN을 추가한 몇 가지 더 자세한 보도 링크가 있으니 음성 처리에 관심이 있기를 바랍니다.

이른바 웹오디오 API


브라우저를 사용하여 낮은 수준의 사운드 머시닝을 제공하는 API입니다.
API는 AudioContext 또는 웹 키트 접두어를 사용하여 제공됩니다.
따라서 초기화const audioCtx= new (window.AudioContext || window.webkitAudioContext)();와 같은 초기화MDN에서 추천.AudioContext에서 baseLatency,outputLatency 등 지연 시간을 얻거나currentTime에서 현재 시간state을 얻거나AudioContext.resume()에서 상태를 얻는다.

사용자 동작에 불이 났습니다. AudioContext.resume()


2010/12/17
웹 오디오 API의 어둠 에서 보듯이 Google Chrome에서는 사용자 동작, 예를 들어 버튼 클릭 등 (Confirm은 사용자 동작으로 간주되지 않는 모양) 으로 부르지 않으면 Promise<> 정상적으로 작동할 수 없습니다.이 반환값은AudioContext.destination이기 때문에 프로그램의 구조 자체를 고칠 필요가 있으니 주의해야 한다.

AudioNode


WebAudioAPI에서는 연결을 통해 AudioNode의 (출력 목적지) 를 계승하여 소리를 생성합니다.
이 연결은 input.connect(output)처럼 연결되지만 이 방법은 연결 목적지 자체로 되돌아오기 때문에 input.connect(output).connect(next)처럼 쓸 수 있다.
기본적으로 AudioContextcreateXXX공장 방법으로 생성된다.

AudioParam


AudioParam의 인터페이스에서 음성을 제어하는 매개 변수를 제공합니다.이들 가운데 defaultValue, minValue, maxValue 등의 설정값(읽기만 가능)과 값 자체value가 설정됐다.
value 변경을 통해 다양한 효과를 낼 수 있습니다.파라미터 이름 자체의 값을 설정에 대입할 수 있으면 오류가 발생할 수 있으니 주의하십시오!
방법을 통해 스케줄링을 할 수도 있다.
샘플링 확률a-rate을 완전히 따르는 매개 변수와 그보다 더 따르지 않는 매개 변수(128개의 샘플마다)k-rate가 있다.(자세한 설정은 문서 등을 확인하십시오.)

구체적인 음원들.


발진기 OscillatorNode


특정 주파수의 파형의 음원type 속성에 따라 파형을 설정할 수 있다.
  • sine-정현파(기본값)
  • square-사각형파
  • sawtooth---톱니파
  • triangle---삼각파
  • custom - 사용자 정의 파형setPeriodicWave(wave) 설정을 통해
  • 네.주파수는 frequencydetune(AudioParam)를 통해 설정할 수 있다.

    AudioBufferSourceNode


    파형 자체 사용AudioBuffer.playbackRate 또는 detune를 통해 음정을 바꿀 수 있다.
    또한, loop(bool 값)에서 순환 설정loopStart(초 단위)시 순환으로 돌아가는 지점, loopEnd(초 단위)로 순환에 들어가는 지점을 설정할 수 있다.
    이번에는 흰색 소음에 사용되는 다음과 같은 느낌의 코드를 사용했다.
    whiteNoise.js
    function makeWhiteNoise(){
        const buffer=audioCtx.createBuffer(2, 5*audioCtx.sampleRate, audioCtx.sampleRate);
        for( let channel=0; channel<buffer.numberOfChannels; channel++ ){
            const data=buffer.getChannelData(channel);
            for( let i=0; i<buffer.length; i++ ){
                data[i]=Math.random()*2.0-1.0; // [ 0: 1.0 ]-> [ -1.0 : 1.0 ]の乱数へ
            }
        }
        
        const bufferSrc=audioCtx.createBufferSource();
        bufferSrc.buffer=buffer;
        bufferSrc.loop=true;
        return bufferSrc;
    }
    

    디코딩 소스 파일


    음원 파일을 사용하고 싶을 때AudicoContext.decodeAudioData(arrayBuffer).
    이것도 예전의 호출 형식과 Promise 형식이 있었지만 지금은 기본적으로 Promise 형식을 지원한다.(Promise를 사용할 수 없는 브라우저는 WebAudioAPI 자체를 지원하지 않음)arrayBuffer XML HTTPRequest 또는 FileReader로 직접 찾기(MDN에 적혀 있음).
    물론 FetchAPI도 이렇게 할 수 있어요.
    decodeAudioData.js
    function decodeAudioData(url){
      fetch(url).then(res=>res.arrayBuffer()).then(arrayBuffer=>{
            return audioCtx.decodeAudioData(arrayBuffer)
        });
    }
    

    Media Stream Audio SourceNode를 위한 마이크 오디오


    getMediaDevices.js
    async function(){
        const stream = await navigator.mediaDevices.getUserMedia({ video: false, audio: true });
        const audioStream=audioCtx.createMediaStreamSource(stream);
        return audioStream;
    }
    
    이런 코드로navigator에서 마이크 흐름을 추출하고 웹오디오 API로 처리할 수 있습니다.

    효과계 노드 소개


    GainNode


    AudioParamgain이 있는 간단한 노드의 음량에 주로 사용됩니다.
    이 밖에도 몇 개의 채널을 통합하는 데 쓰인다.

    DelayNode


    AudioParamdelayTime이 있는 노드에서 신호를 지연합니다.
    주의점은 완전한 지연이기 때문에 단독으로 사용할 수 없습니다. 반드시 무엇으로 순환해야만 사용할 수 있습니까? 여기 참고g200kg의 웹 오디오 API 해설 >13.지연 사용 방법는 다음과 같은 두 가지 예를 들었습니다.

    Delay 모듈


    이른바 효과기인 딜레이 모듈이 지연 신호를 혼합해 출력하기 때문에 이런 구조가 만들어졌다.
    SimpleDelay.js
    class SimpleDelay{
        constructor(audioCtx){
            this.inputNode=audioCtx.createGain();
            this.delayNode=audioCtx.createDelay();
            this.feedbackNode=audioCtx.createGain();
            this.dryNode=audioCtx.createGain();
            this.wetNode=audioCtx.createGain();
    
            this.delayNode.delayTime.value=1.0;
            this.feedbackNode.gain.value=0.5;
            this.dryNode.gain.value=0.8;
            this.wetNode.gain.value=0.2;
    
            this.inputNode.connect(this.delayNode).connect(this.feedbackNode).connect(this.delayNode);
            this.delayNode.connect(this.wetNode);
            this.inputNode.connect(this.dryNode);
        }
    
        connect(next){
            this.dryNode.connect(next);
            this.wetNode.connect(next);
            return next;
        }
    
        get input(){ return this.inputNode; }
    
        get delayTime(){ return this.delayNode.delayTime; }
        get feedback(){ return this.feedbackNode.gain; }
    
        get mix(){ return this.wetNode.gain.value; }
        set mix(value){
            if( value<0 && 1<value ) new Error(`Invalid mix value ${val}`);
            this.wetNode.gain.value=value;
            this.dryNode.gain.value=1.0-value;
        }
    }
    
    있긴 하지만g200kg님도 맞춤형 노드 만드는 방법기존오디오노드를혼자상속받고new를두드릴 필요가있어특별하므로각노드를상속받지 않고반원으로하는 방법을취했다.결과적으로 입력단이 체인을 사용하는connect는 사용할 수 없습니다.
    각 오디오노드의 속성인 오디오노드를 get xxx() 형식으로 자신의 것으로 위장했다.
    또한 출력 측connect은 안에 두 개의 출구 연결 노드를 연결하기 때문에 여기서 체인을 사용할 수 있다.

    AudioParam에 연결, 로터리 효과기 Chorus


    오디오노드는 오디오팔람에 연결될 수 있으며, 이를 통해 델리타임 같은 것을 흔들어 이른바 합창을 실현할 수 있다.
    Chorus.js
    class Chorus{
        constructor(audioCtx){
            this.inputNode=audioCtx.createGain();
            this.delayNode=audioCtx.createDelay();
            this.mixNode=audioCtx.createGain();
    
            this.lfo=audioCtx.createOscillator();
            this.depthNode=audioCtx.createGain();
    
            this.lfo.frequency.value=5;
            this.depthNode.gain.value=0.005;
            this.mixNode.gain.value=0.2;
    
            this.lfo.connect(this.depthNode).connect(this.delayNode.delayTime); // この部分
            this.inputNode.connect(this.delayNode).connect(this.mixNode);
        }
    
        connect(next){
            this.mixNode.connect(next);
            this.input.connect(next);
            return next;
        }
    
        get input(){ return this.inputNode; }
    
        get speed(){ return this.lfo.frequency; }
        get depth(){ return this.depthNode.gain; }
        get mix(){ return this.mixNode.gain; }
    }
    
    lfo는 Low Frequency Oscillator라는 뜻으로 현실의 효과기 등에 자주 등장한다.

    BiquadFilterNode(이중 필터)


    일반 필터
    주파수 설정 (frequency 및 detune), Q 값,gain을 나타내는 오디오 Param, 종류 type (속성 값) 이 있습니다.

    BiquadFilterNode의 종류

  • lowpass
  • highpass
  • bandpass
  • lowshelf
  • highshelf
  • peaking
  • notch
  • allpass
  • 주파수 특성BiquadFilterNode.getFrequencyResponse 획득 가능

    전체 사용 방법


    index.js
    onst audioCtx = new (window.AudioContext || window.webkitAudioContext)();
    
    window.addEventListener('DOMContentLoaded', async ()=>{
        const masterGain=audioCtx.createGain();
        bindValue(document.getElementById('master-vol'), masterGain.gain);
        const sourceInput=audioCtx.createGain();
    
        const simpleDelay=new SimpleDelay(audioCtx);
        bindValue(document.getElementById("delay-time"), simpleDelay.delayTime);
        bindValue(document.getElementById("feedback-gain"), simpleDelay.feedback);
        bindProp(document.getElementById('delay-mix'), simpleDelay, 'mix');
        
        const oscillator=audioCtx.createOscillator();
        oscillator.start();
        bindValue(document.getElementById('oscillator-freq'), oscillator.frequency);
        bindSelect(document.getElementById('oscillator-type'), oscillator, 'type');
        
        oscillator.connect(sourceInput).connect(simpleDelay.input); // can not connect as chain
        simpleDelay.connect(masterGain).connect(audioCtx.destination);
        
        document.getElementById('start-btn', ()=>{ oscillator.start() });
    });
    
    function bindValue(element, param){ element.addEventListener('change', ()=>{ param.value=element.value; }); }
    function bindProp(element, param, prop){ element.addEventListener('change', ()=>{ param[prop]=element.value; }); }
    function bindSelect(select, node, prop){ select.addEventListener('change', ()=>{ node[prop]=[ ...select.children ].find(a=> a.selected).value; }); }
    
    
    이렇게 사용하세요.bindValue AudioParam의 값value과 HTML Elementinput[type="range"]을 직접 제한bindSelect는 발진기 유형을 HTML Element의 select 라벨과 유사하게 결합시킨다.
    Delay 모듈의 mixvalue 속성이 아니기 때문에 다른 함수를 준비했습니다.
    (이것들은 모두 일부라서 복제만 하면 움직이지 않을 것 같다.)

    후기


    먼저 기초 개념을 겸비한 해설을 겸비한 간단한 것들의 제작 방법을 설명한다.
    더 자세한 노드와 다른 해설은 이 글에서도 자주 언급된g200kg 홈페이지을 참조하십시오.
    Web Sounder간단한 샘플을 첨부하여 해설을 진행한다.
    더 자세한 설명은 W3C 기사(일본어) 더 정확한 정보W3C를 참조하십시오.
    다른 노드 해설 등 추가 예정

    좋은 웹페이지 즐겨찾기