我正在开发一个网络应用程序,用户可以与数字乐器 UI 交互以播放不同的音符,这些音符最终会传输到我的后端。我正在使用 Web Audio API 将正在播放的音符转换为 AudioBufferSourceNodes,并尝试将播放的音频传递到我的(MediaRecorder API)录音机正在监听的流,以便生成所有音频的最终录音播放注意到用户已经玩过。
最终录音包含所有演奏的音符,问题是它没有考虑节点之间的暂停。例如,如果用户播放持续 1 秒的音符,等待 5 秒,然后再次播放相同的音符...最终录音将在 2 秒的时间内依次播放这两个音符,而不是第一次播放音符,等待 5 秒,然后第二次播放音符。
这是我的 WebAudio API 和 MediaRecorder API 代码:
//initialize recording stream components
let chunks = [];
let context = new AudioContext();
let stream_destination = context.createMediaStreamDestination();
let recording = new MediaRecorder(stream_destination.stream);
recording.ondataavailable = event => {
chunks.push(event.data)
}
recording.onstop = () => {
document.getElementById("recording").src = URL.createObjectURL(new Blob(chunks,{'type':'audio/mp3'}))
}
document.getElementById("start").addEventListener("click", () => { recording.start(1000); console.log("recording started"); })
document.getElementById("stop").addEventListener("click", () => { recording.stop(); console.log("recording stopped"); })
// play audio file to user and create sourceNode to add to MediaRecorder
document.getElementById('sound-button').addEventListener('click', () => {
const audioFilePath = './media/temp1.mp3';
const audio = new Audio(audioFilePath);
audio.play();
let request = new XMLHttpRequest();
request.open("GET", audioFilePath, true);
request.responseType = "arraybuffer";
request.onload = () => {
let audioData = request.response;
context.decodeAudioData(
audioData,
(buf) => {
// add the played buffer to buffer history
recordedAudioBuffers.push(buf);
console.log("buffer was succesfully added to buffer history. buffer history: " + JSON.stringify(recordedAudioBuffers));
const sourceNode = new AudioBufferSourceNode(context, {buffer: buf})
sourceNode.connect(stream_destination);
sourceNode.start();
}
)
}
request.send();
});
最初,我认为我可以操纵 sourceNode.start() 方法的计时参数来达到我想要的结果,但仍然没有得到我想要的最终记录。
我还研究了是否可以在代表用户演奏的音符的源节点之间集成“空”源节点,以模拟我在最终录音中寻找的音符之间的停顿,但在研究了在线选项之后,这似乎不必要地使我的代码/实现变得复杂。
据我所知这只是 Firefox 中的一个问题。可以用无声的
ConstantSourceNode
来修复。
const constantSourceNode = new ConstantSourceNode(
context,
{ offset: 0 }
);
constantSourceNode.connect(stream_destination);
constantSourceNode.start();