Веб-аудио api предоставляет метод .stop()
, чтобы остановить звук. Я хочу, чтобы мой звук уменьшался в объеме перед остановкой. Для этого я использовал узел усиления. Однако я сталкиваюсь с такими странными проблемами, когда некоторые звуки просто не играют, и я не могу понять, почему.Веб-аудио api, стоп-звук изящно
Вот упрощенных вниз вариант того, что я делаю:
https://jsfiddle.net/01p1t09n/1/
Вы услышите, что если вы удалите строку с setTimeout()
что каждый звук играет. Когда setTimeout не воспроизводится не каждый звук. Что меня действительно смущает, так это то, что я использую push
и shift
соответственно, чтобы найти правильный источник звука, однако кажется, что это другое, что перестает играть. Единственное, что я вижу, это то, что AudioContext.decodeAudioData
не является синхронным. Просто попробуйте jsfiddle, чтобы лучше понять и, очевидно, надеть гарнитуру.
Вот код jsfiddle:
let url = "https://raw.githubusercontent.com/gleitz/midi-js-soundfonts/gh-pages/MusyngKite/acoustic_guitar_steel-mp3/A4.mp3";
let soundContainer = {};
let notesMap = {"A4": [] };
let _AudioContext_ = AudioContext || webkitAudioContext;
let audioContext = new _AudioContext_();
var oReq = new XMLHttpRequest();
oReq.open("GET", url, true);
oReq.responseType = "arraybuffer";
oReq.onload = function (oEvent) {
var arrayBuffer = oReq.response;
makeLoop(arrayBuffer);
};
oReq.send(null);
function makeLoop(arrayBuffer){
soundContainer["A4"] = arrayBuffer;
let currentTime = audioContext.currentTime;
for(let i = 0; i < 10; i++){
//playing at same intervals
play("A4", currentTime + i * 0.5);
setTimeout(() => stop("A4"), 500 + i * 500); //remove this line you will hear all the sounds.
}
}
function play(notePlayed, start) {
audioContext.decodeAudioData(soundContainer[notePlayed], (buffer) => {
let source;
let gainNode;
source = audioContext.createBufferSource();
gainNode = audioContext.createGain();
// pushing notes in note map
notesMap[notePlayed].push({ source, gainNode });
source.buffer = buffer;
source.connect(gainNode);
gainNode.connect(audioContext.destination);
gainNode.gain.value = 1;
source.start(start);
});
}
function stop(notePlayed){
let note = notesMap[notePlayed].shift();
note.source.stop();
}
Это просто объяснить, почему я делаю это так, вы можете пропустить его, это просто объяснить, почему я не 't use stop()
Причина, по которой я все это делаю, потому что я хочу прекратить звук изящно, поэтому, если есть возможность сделать это без использования setTimeout, я бы с радостью принял Это.
В основном у меня есть карта наверху, содержащая мои звуки (примечания типа A1, A # 1, B1, ...).
soundMap = {"A": [], "lot": [], "of": [], "sounds": []};
и play()
ГЦТ, где я заполнить массивы один раз я играю звуки:
play(sound) {
// sound is just { soundName, velocity, start}
let source;
let gainNode;
// sound container is just a map from soundname to the sound data.
this.audioContext.decodeAudioData(this.soundContainer[sound.soundName], (buffer) => {
source = this.audioContext.createBufferSource();
gainNode = this.audioContext.createGain();
gainNode.gain.value = sound.velocity;
// pushing sound in sound map
this.soundMap[sound.soundName].push({ source, gainNode });
source.buffer = buffer;
source.connect(gainNode);
gainNode.connect(this.audioContext.destination);
source.start(sound.start);
});
}
А теперь часть, которая останавливает звуки:
stop(sound){
//remember above, soundMap is a map from "soundName" to {gain, source}
let dasound = this.soundMap[sound.soundName].shift();
let gain = dasound.gainNode.gain.value - 0.1;
// we lower the gain via incremental values to not have the sound stop abruptly
let i = 0;
for(; gain > 0; i++, gain -= 0.1){ // watchout funky syntax
((gain, i) => {
setTimeout(() => dasound.gainNode.gain.value = gain, 50 * i);
})(gain, i)
}
// we stop the source after the gain is set at 0. stop is in sec
setTimeout(() => note.source.stop(), i * 50);
}
_ «Единственное, что я вижу, это то, что AudioContext.decodeAudioData не является синхронным». _ Вы правы: '.decodeAudioData' не является синхронным. – guest271314
@ guest271314 ну, черт возьми, мне придется переделать все – Ced
Что ожидается результат вызова 'setTimeout' в цикле' for' в jsfiddle, который не вызывается в закрытии? '.decodeAudioData()' также возвращает 'Promise', где' .then() 'может быть закодирован для получения декодированных аудиоданных. – guest271314