Web Audio API dołączanie / łączenie różnych Audiobufferów i odtwarzanie ich jako jednego utworu
Grałem z Web Audio API i próbuję załadować wiele części utworu i dołączyć je do nowego ArrayBuffer, a następnie użyć tego ArrayBuffer do odtwarzania wszystkich części jako jeden utwór. W poniższym przykładzie używam tych samych danych utworu (które są małą pętlą) zamiast różnych części utworu.
Problem w tym, że nadal gra tylko raz zamiast dwa razy i nie wiem dlaczego.
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);
2 answers
Problem w Twoim kodzie polega na tym, że kopiujesz i dodajesz kolejną kopię pliku MP3 na sam koniec. Ta kopia zostaje skutecznie zignorowana przez dekoder - to nie są surowe dane bufora, to tylko przypadkowe fałszywe śmieci w strumieniu plików, po idealnie kompletnym pliku MP3.
Najpierw dekoduj dane audio do Audiobuffera, a następnie dołącz bufory audio do nowego Audiobuffera. Wymaga to trochę restrukturyzacji twojego kod.
To co chcesz zrobić to:
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);
Jest niewielka luka w odtwarzaniu-to dlatego, że masz prawie 50ms ciszy na początku próbki dźwięku, a nie z powodu problemów z zapętleniem.
Mam nadzieję, że to pomoże!Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-03 22:14:29
Jeśli chcesz dodać / połączyć listę buforów z tablicy (nie tylko 2), Oto rozwiązanie. Właśnie trochę poprawiłem kod @Cwilso (dzięki za pomoc ;)
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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-12 14:14:00