网络音频API播放一个接一个的笔记



我对Javascript比较陌生,我曾尝试使用WebAudio API播放笔记。音符确实在演奏,但不是我想要的那样。我正在试着让音符在彼此之后播放。代码中的每个节点都有一个频率数组。然后,我使用for循环来遍历这个数组,并使用函数playNote播放频率。我尝试使用timeOut来添加playNote在for循环中调用的延迟,但似乎不起作用。

class Node {
constructor(x, y, radius, color, frequency){
this.x = x
this.y = y
this.radius = radius
this.color = color
this.frequency = frequency
}
}
const player1 = new Node(100, 100, 30, 'blue',[1047])
const player2 = new Node(200, 100, 30, 'red',[1047, 1047])
var listOfNodes = []
listOfNodes.push(player1)
listOfNodes.push(player2)
function playNote(freq) {
oscillator = audioCtx.createOscillator()
gain = audioCtx.createGain()
oscillator.type = 'sine'
oscillator.connect(gain)
oscillator.frequency.value = freq
gain.connect(audioCtx.destination)
oscillator.start(0)
gain.gain.exponentialRampToValueAtTime(0.00001, audioCtx.currentTime + 1)
}
listOfNodes.forEach(node => {
var i;
for (i = 0; i < node.frequency.length; i++) {
setTimeout(function() {
playNote(node.frequency[i])
}, 2000 * i);
}
}
);

有很多方法可以做到这一点。例如,您可以为每个playNote设置不同的开始时间。像这样:

function playNote(freq, time) {
oscillator = audioCtx.createOscillator()
gain = audioCtx.createGain()
oscillator.type = 'sine'
oscillator.connect(gain)
oscillator.frequency.value = freq
gain.connect(audioCtx.destination)
oscillator.start(audioCtx.currentTime + time)
gain.gain.exponentialRampToValueAtTime(0.00001, audioCtx.currentTime + 1 + time)
}
for (i = 0; i < node.frequency.length; i++) {       
playNote(node.frequency[i], i)          
}

或者使用当一个音符结束时执行的递归函数。但为此,您需要指定oscillator.stop(audioCtx.currentTime + sometime)的实际结束时间,而不是那个丑陋的破解:(gain.gain.exponentialRampToValueAtTime(0.00001, audioCtx.currentTime + 1 + time)

function playNote(freq) {
oscillator = audioCtx.createOscillator()
gain = audioCtx.createGain()
oscillator.type = 'sine'
oscillator.connect(gain)
oscillator.frequency.value = freq
gain.connect(audioCtx.destination)
oscillator.start(audioCtx.currentTime)
oscillator.stop(audioCtx.currentTime + 1)
oscillator.addEventListener('ended', () => {playNote(nextFrequency)}, { once: true });
}

但我认为最好的方法是使用现代javascript功能:Promises和异步等待

const audioCtx = new AudioContext();
class Node {
constructor(x, y, radius, color, frequency){
this.x = x
this.y = y
this.radius = radius
this.color = color
this.frequency = frequency
}
}
const player1 = new Node(100, 100, 30, 'blue',[1047])
const player2 = new Node(200, 100, 30, 'red',[1047, 1047])
var listOfNodes = []
listOfNodes.push(player1)
listOfNodes.push(player2)
function playNote(freq) {
return new Promise((resolve) => {
oscillator = audioCtx.createOscillator()
gain = audioCtx.createGain()
oscillator.type = 'sine'
oscillator.connect(gain)
oscillator.frequency.value = freq
gain.connect(audioCtx.destination)
oscillator.start(audioCtx.currentTime)
oscillator.stop(audioCtx.currentTime + 1)
oscillator.addEventListener('ended', resolve, { once: true });
})
}
async function play() {
for (const node of listOfNodes) {
for (const frequency of node.frequency) {
console.log(`note with frequenty ${frequency} started`)
await playNote(frequency);
console.log(`note with frequency ${frequency} ended`)
}
}
}
play();

相关内容

最新更新