9

Ich habe mit der Web Audio API gespielt und ich versuche, mehrere Teile eines Songs zu laden und sie an einen neuen ArrayBuffer anhängen und dann verwenden ArrayBuffer zum Abspielen aller Teile als ein Lied. Im folgenden Beispiel verwende ich die gleichen Song-Daten (das ist eine kleine Schleife) anstelle von verschiedenen Teilen eines Songs.Web Audio API anfügen/verketten verschiedene AudioBuffers und spielen sie als ein Lied

Das Problem ist, dass es immer noch nur einmal statt zwei Mal spielt und ich weiß nicht warum.

Download song

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); 

Antwort

15

Das Problem in Ihrem Code ist, dass Sie kopieren und eine weitere Kopie der MP3-Datei auf das Ende selbst anhängt. Diese Kopie wird vom Dekoder effektiv ignoriert - es handelt sich nicht um rohe Pufferdaten, sondern um zufälligen, unerwünschten Junk im Dateistrom, der einer vollkommen vollständigen MP3-Datei folgt.

Sie müssen zuerst die Audiodaten in einen AudioBuffer decodieren und dann die Audiopuffer zu einem neuen AudioBuffer zusammenfügen. Dies erfordert ein wenig Umstrukturierung Ihres Codes.

Was möchten Sie tun, ist dies:

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); 

Es gibt eine leichte Wiedergabe Lücke - das ist, weil Sie am Anfang Ihrer Hörbeispiel fast 50 ms der Stille, nicht aufgrund Looping Fragen.

Hoffe, das hilft!

+1

Danke, Ihr Kommentar hat mir geholfen! http://72lions.github.com/PlayingChunkedMP3-WebAudioAPI/ – 72lions

+0

@cwilso Ist es möglich, mehrere AudioBufferSourceNodes zu verschiedenen Zeiten der Wiedergabe zu einem einzigen zu verbinden? –

+0

Nun, Sie können sie einfach an das gleiche Ziel verbinden. Ich denke, das hat den Effekt, den Sie suchen. – cwilso