Фон: я создал OscillatorNode, запустил его с .start()
и установил время его остановки с .stop()
. Он представляет собой тон, который длится 1 сек c. Но я хочу иметь возможность остановить генератор на ранней стадии, в ответ на щелчок мышью пользователя, то есть, чтобы остановить тональный сигнал до времени окончания, которое было установлено .stop()
. Мой подход состоит в том, чтобы вызвать новый метод .stop()
с событием onmouseup
.
Проблема: вместо этого щелчок мыши приводит к InvalidStateError: «Объект находится в недопустимом состоянии». Я предполагаю, что это потому, что я применяю второй .stop()
метод к одному OscillatorNode. OscillatorNodes, очевидно, может поддерживать только один .start()
вызов и один .stop()
вызов.
Вопрос: действительно ли нет способа обновить время остановки, установленное .stop()
метод? Это кажется странным. (Мне известны некоторые потенциальные обходные пути, такие как установка усиления на ноль; эти обходные пути были неприемлемы. Я действительно чувствую, что OscillatorNode должен иметь возможность программно прерваться.)
Увеличенный контекст: это часть пользовательский интерфейс, в котором мелодии воспроизводятся в ответ на ввод пользователя. В настоящее время, если пользователь переключает тоны слишком быстро, у нас возникают проблемы с перекрывающимися звуковыми сигналами, вызывающими неприятные акустические помехи c. Мне нужен любой воспроизводимый в данный момент звуковой сигнал, чтобы остановить его, как только будет запущен новый тон.
var ac = new (window.AudioContext || window.webkitAudioContext)();
var gainNode=ac.createGain();
gainNode.connect(ac.destination)
var playing=false
var oscillator
function setFrequency() { // captures the frequency from an input slider
frequency=document.getElementById("frequency").value
document.getElementById("frequency_log").innerHTML=frequency
}
function play(frequency) { // plays 0.5s tone (w/gain envelope) at given frequency
if(playing){ // stop currently playing tone
oscillator.stop() // !! THIS IS WHAT GIVES THE INVALID STATE ERROR !!
playing=false
}
if (!playing){ // play tone
oscillator=ac.createOscillator();
oscillator.onended=function(){playing=false}
oscillator.connect(gainNode)
oscillator.frequency.value = frequency;
gainNode.gain.setValueAtTime(0.001,0);
gainNode.gain.exponentialRampToValueAtTime(0.8,ac.currentTime+0.1);
gainNode.gain.setValueAtTime(0.8,ac.currentTime+0.3);
gainNode.gain.exponentialRampToValueAtTime(0.1, ac.currentTime+0.4);
gainNode.gain.exponentialRampToValueAtTime(0.001, ac.currentTime+0.5);
oscillator.start();
playing=true
oscillator.stop(ac.currentTime+0.5)
}
}
<span class="math-container">```</span>