Web Audio API附加/连接不同的audiobuffer并将它们作为一首歌曲播放
Web Audio API append/concatenate different AudioBuffers and play them as one song
我一直在玩Web音频API,我试图加载一首歌的多个部分,并将它们附加到一个新的ArrayBuffer,然后使用ArrayBuffer作为一首歌播放所有部分。在下面的例子中,我使用了相同的歌曲数据(这是一个小循环),而不是歌曲的不同部分。
问题是它仍然只播放一次而不是两次,我不知道为什么。
下载歌曲
function init() {
/**
* Appends two ArrayBuffers into a new one.
*
* @param {ArrayBuffer} buffer1 The first buffer.
* @param {ArrayBuffer} buffer2 The second buffer.
*/
function appendBuffer(buffer1, buffer2) {
var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
tmp.set( new Uint8Array(buffer1), 0);
tmp.set( new Uint8Array(buffer2), buffer1.byteLength);
return tmp;
}
/**
* Loads a song
*
* @param {String} url The url of the song.
*/
function loadSongWebAudioAPI(url) {
var request = new XMLHttpRequest();
var context = new webkitAudioContext();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
/**
* Appends two ArrayBuffers into a new one.
*
* @param {ArrayBuffer} data The ArrayBuffer that was loaded.
*/
function play(data) {
// Concatenate the two buffers into one.
var a = appendBuffer(data, data);
var buffer = a.buffer;
var audioSource = context.createBufferSource();
audioSource.connect(context.destination);
//decode the loaded data
context.decodeAudioData(buffer, function(buf) {
console.log('The buffer', buf);
audioSource.buffer = buf;
audioSource.noteOn(0);
audioSource.playbackRate.value = 1;
});
};
// When the song is loaded asynchronously try to play it.
request.onload = function() {
play(request.response);
}
request.send();
}
loadSongWebAudioAPI('http://localhost:8282/loop.mp3');
}
window.addEventListener('load',init,false);
代码中的问题是,您正在复制MP3文件的另一个副本并将其附加到其末尾。该副本被解码器有效地忽略了-它不是原始缓冲区数据,它只是文件流中随机的虚假垃圾,后面是一个完美完整的MP3文件。
您需要做的是首先将音频数据解码到AudioBuffer中,然后将音频缓冲区附加到一个新的AudioBuffer中。这需要对代码进行一些重构。
你要做的是:
var context = new webkitAudioContext();
function init() {
/**
* Appends two ArrayBuffers into a new one.
*
* @param {ArrayBuffer} buffer1 The first buffer.
* @param {ArrayBuffer} buffer2 The second buffer.
*/
function appendBuffer(buffer1, buffer2) {
var numberOfChannels = Math.min( buffer1.numberOfChannels, buffer2.numberOfChannels );
var tmp = context.createBuffer( numberOfChannels, (buffer1.length + buffer2.length), buffer1.sampleRate );
for (var i=0; i<numberOfChannels; i++) {
var channel = tmp.getChannelData(i);
channel.set( buffer1.getChannelData(i), 0);
channel.set( buffer2.getChannelData(i), buffer1.length);
}
return tmp;
}
/**
* Loads a song
*
* @param {String} url The url of the song.
*/
function loadSongWebAudioAPI(url) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
/**
* Appends two ArrayBuffers into a new one.
*
* @param {ArrayBuffer} data The ArrayBuffer that was loaded.
*/
function play(data) {
//decode the loaded data
context.decodeAudioData(data, function(buf) {
var audioSource = context.createBufferSource();
audioSource.connect(context.destination);
// Concatenate the two buffers into one.
audioSource.buffer = appendBuffer(buf, buf);
audioSource.noteOn(0);
audioSource.playbackRate.value = 1;
});
};
// When the song is loaded asynchronously try to play it.
request.onload = function() {
play(request.response);
}
request.send();
}
loadSongWebAudioAPI('loop.mp3');
}
window.addEventListener('load',init,false);
有一个轻微的播放间隙-这是因为你在声音样本开始时有近50ms的沉默,而不是由于循环问题。
希望这对你有帮助!
如果您需要从数组(不仅仅是2)中追加/连接缓冲区列表,这里有一个解决方案。我刚刚调整了一点@Cwilso代码(感谢您的帮助;)
function concatBuffer(_buffers) {
// _buffers[] is an array containig our audiobuffer list
var buflengh = _buffers.length;
var channels = [];
var totalDuration = 0;
for(var a=0; a<buflengh; a++){
channels.push(_buffers[a].numberOfChannels);// Store all number of channels to choose the lowest one after
totalDuration += _buffers[a].duration;// Get the total duration of the new buffer when every buffer will be added/concatenated
}
var numberOfChannels = channels.reduce(function(a, b) { return Math.min(a, b); });;// The lowest value contained in the array channels
var tmp = context.createBuffer(numberOfChannels, context.sampleRate * totalDuration, context.sampleRate);// Create new buffer
for (var b=0; b<numberOfChannels; b++) {
var channel = tmp.getChannelData(b);
var dataIndex = 0;
for(var c = 0; c < buflengh; c++) {
channel.set(_buffers[c].getChannelData(b), dataIndex);
dataIndex+=_buffers[c].length;// Next position where we should store the next buffer values
}
}
return tmp;
}
相关文章:
- Last.fm API发送2个曲目时,我要求一个,如果我正在听一首歌
- 在for循环中另一个音频结束后播放一段时间的音频
- HTML5<音频>:点击下一首歌曲时停止加载/缓冲
- 滚动播放视频,但只能播放一次
- 制作一个html5音频播放列表,自动播放一首又一首歌曲
- 带有jQuery的音频HTML5播放下一首曲目
- 在iPad 2上播放一次后,视频海报消失
- 对文本区域段落的每一首行应用缩进
- 带有播放列表的HTML和JS播放器仅播放一种音乐
- 如何阻止 CSS3 动画在播放一次后运行并调用新动画
- JavaScript:我的声音只播放一次
- 获取 timeOut() 以每秒从数组中播放一首歌曲
- 图表.js饼图动画,在页面中的某个位置通过垂直滚动播放一次
- 在同一个html5音频播放器中播放多首音乐的最佳想法是什么
- 我想在歌曲结束后在默认音频播放器中播放一首流行音乐,任何人都可以帮我编写代码
- 音频播放器-一次只播放一首曲目,不起作用
- AngularJS Cordova Media不;不要总是播放下一首歌
- 音频自动播放下一首歌曲时,上一首完成
- Soundcloud Flash小部件,试图在页面上播放下一首歌曲
- Web Audio API附加/连接不同的audiobuffer并将它们作为一首歌曲播放