Веб-аудио - генератор AnalyserNode - PullRequest
0 голосов
/ 31 марта 2020

Я пытаюсь добавить AnalyserNode и визуализировать выходной звук для примера веб-аудио, который я сделал, но не могу понять, как. Я думаю, что не передаю правильный источник в анализатор (?)

Здесь для полного кода: https://jsfiddle.net/kepin95043/1ub0sjo3/

    <script>
        var fs = 2000;
        var gain = 0.2;

        class Sound {
            constructor(context) {
                this.context = context;
            }

            init() {
                this.oscillator = this.context.createOscillator();
                this.oscillator.frequency.value = fs;
                this.gainNode = this.context.createGain();
                this.oscillator.connect(this.gainNode);
                this.gainNode.connect(this.context.destination);

            }

            play(value) {
                this.init();
                this.gainNode.gain.setValueAtTime(gain, this.context.currentTime);
                this.oscillator.start();
            }

            stop() {
                this.gainNode.gain.exponentialRampToValueAtTime(0.001, this.context.currentTime + 1);
                this.oscillator.stop(this.context.currentTime + 1);
            }

        }

        var context = new AudioContext();
        var sound = new Sound(context);
        sound.init();
        var wave = 'sine';
        var state = 'paused';

        var waveSelectors = document.querySelectorAll('.waveform');
        var playBtn = document.querySelector('#play');
        var container = document.querySelector('.container');
        waveSelectors.forEach(function(button) {
            button.addEventListener('click', function() {
                cleanClass('active');
                wave = button.dataset.wave;
                sound.oscillator.type = wave;
                button.classList.add('active');
            })
        })

        playBtn.addEventListener('click', function() {

            context.resume().then(() => {
                console.log('Playback resumed successfully');
            });
            if (playBtn.text == 'Play') {
                sound.play();
                sound.oscillator.type = wave;
                playBtn.text = 'Pause';
            } else {
                sound.stop();
                playBtn.text = 'Play';
            }
        })

        function cleanClass(rclass) {
            waveSelectors.forEach(function(button) {
                button.classList.remove(rclass);
            })
        }

        function changeFs(val) {
            fs = val;
            var output = document.getElementById("fsValue");
            output.innerHTML = val;
            sound.stop();
            sound.play();
            console.log(val);
        };

        function changeGain(val) {
            gain = val;
            var output = document.getElementById("gainValue");
            output.innerHTML = val;
            sound.stop();
            sound.play();
            console.log(val);
        };

    var masterGain;
    masterGain = context.createGain();
    masterGain.connect(context.destination);

    // analyser
    var analyser = context.createAnalyser();
    masterGain.connect(analyser);

    var waveform = new Float32Array(analyser.frequencyBinCount);
    analyser.getFloatTimeDomainData(waveform);

    (function updateWaveform() {
      requestAnimationFrame(updateWaveform);
      analyser.getFloatTimeDomainData(waveform);
    }());

    var spectrum = new Uint8Array(analyser.frequencyBinCount);
    (function updateSpectrum() {
      requestAnimationFrame(updateSpectrum);
      analyser.getByteFrequencyData(spectrum);
    }());


    // oscilloscope
    var scopeCanvas = document.getElementById('canvas');
    scopeCanvas.width = waveform.length;
    //scopeCanvas.height = 200;
    scopeCanvas.height = scopeCanvas.width * 0.33;
    var scopeContext = scopeCanvas.getContext('2d');

    (function drawOscilloscope() {
      requestAnimationFrame(drawOscilloscope);
      scopeContext.clearRect(0, 0, scopeCanvas.width, scopeCanvas.height);
      scopeContext.strokeStyle="white"; // Green path
      scopeContext.beginPath();
      for (var i = 0; i < waveform.length; i++) {
        var x = i;
        var y = (0.5 + waveform[i] / 2) * scopeCanvas.height;
        if (i === 0) {
          scopeContext.moveTo(x, y);
        } else {
          scopeContext.lineTo(x, y);
        }
      }
      scopeContext.stroke();
    }());

    </script>

Может ли кто-нибудь помочь мне определить, что я делаю не так? Заранее спасибо!

PS: откройте его с помощью Firefox. У меня не работает браузеры на базе Chromium.

Вот рабочий пример: https://codepen.io/dennisgaebel/pen/YEwLaL

Ответы [ 2 ]

0 голосов
/ 01 апреля 2020

Вот полный рабочий код скрипта:

var fs = 2000;
var gain = 0.2;

class Sound {
    constructor(context) {
        this.context = context;
    }

    init() {
        this.oscillator = this.context.createOscillator();
        this.oscillator.frequency.value = fs;
        this.gainNode = this.context.createGain();
        this.oscillator.connect(this.gainNode);
        this.gainNode.connect(this.context.destination);
    }
    play(value) {
        this.init();
        this.gainNode.gain.setValueAtTime(gain, this.context.currentTime);
        this.oscillator.start();
        // connect analyser to the gainedSource
        this.gainNode.connect(analyser);
        // for the non gainedSource
        //this.gainNode.connect(analyser);
    }
    stop() {
        this.gainNode.gain.exponentialRampToValueAtTime(0.001, this.context.currentTime + 1);
        this.oscillator.stop(this.context.currentTime + 1);
    }
}

var context = new AudioContext();
var sound = new Sound(context);
sound.init();
var wave = 'sine';
var state = 'paused';

var waveSelectors = document.querySelectorAll('.waveform');
var playBtn = document.querySelector('#play');
var container = document.querySelector('.container');
waveSelectors.forEach(function(button) {
    button.addEventListener('click', function() {
        cleanClass('active');
        wave = button.dataset.wave;
        sound.oscillator.type = wave;
        button.classList.add('active');
    })
})

playBtn.addEventListener('click', function() {
    context.resume().then(() => {
        console.log('Playback resumed successfully');
    });
    if (playBtn.text == 'Play') {
        sound.play();
        sound.oscillator.type = wave;
        playBtn.text = 'Pause';
    } else {
        sound.stop();
        playBtn.text = 'Play';
    }
})

function cleanClass(rclass) {
    waveSelectors.forEach(function(button) {
        button.classList.remove(rclass);
    })
}

function changeFs(val) {
    fs = val;
    var output = document.getElementById("fsValue");
    output.innerHTML = val;
    sound.stop();
    sound.play();
    console.log(val);
};

function changeGain(val) {
    gain = val;
    var output = document.getElementById("gainValue");
    output.innerHTML = val;
    sound.stop();
    sound.play();
    console.log(val);
};


// analyser node
var analyser = context.createAnalyser();
var waveform = new Float32Array(analyser.frequencyBinCount);
analyser.getFloatTimeDomainData(waveform);

(function updateWaveform() {
    requestAnimationFrame(updateWaveform);
    analyser.getFloatTimeDomainData(waveform);
}());

var spectrum = new Uint8Array(analyser.frequencyBinCount);
(function updateSpectrum() {
    requestAnimationFrame(updateSpectrum);
    analyser.getByteFrequencyData(spectrum);
}());


// oscilloscope
var scopeCanvas = document.getElementById('canvas');
scopeCanvas.width = waveform.length;
scopeCanvas.height = scopeCanvas.width * 0.33;
var scopeContext = scopeCanvas.getContext('2d');

(function drawOscilloscope() {
    requestAnimationFrame(drawOscilloscope);
    scopeContext.clearRect(0, 0, scopeCanvas.width, scopeCanvas.height);
    scopeContext.strokeStyle = "white"; // Green path
    scopeContext.beginPath();
    for (var i = 0; i < waveform.length; i++) {
        var x = i;
        var y = (0.5 + waveform[i] / 2) * scopeCanvas.height;
        if (i === 0) {
            scopeContext.moveTo(x, y);
        } else {
            scopeContext.lineTo(x, y);
        }
    }
    scopeContext.stroke();
}());
0 голосов
/ 01 апреля 2020

Вы создаете объект Sound, а также masterGain, который подключен к вашему AnalyserNode. Но я не вижу, где звук соединяется с masterGain. Без этого ваш узел анализатора просто замолкает.

...