9

Ho giocato con l'API Web Audio e sto provando a caricare più parti di un brano e aggiungerli a un nuovo ArrayBuffer e quindi utilizzarlo ArrayBuffer per suonare tutte le parti come una canzone. Nell'esempio seguente sto usando gli stessi dati di song (che è un piccolo loop) invece di parti diverse di una song.Le API Web Audio aggiungono/concatenano AudioBuffer diversi e li suonano come un brano

Il problema è che suona ancora una volta invece di due volte e non so perché.

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

risposta

15

Il problema nel codice è che si sta copiando e aggiungendo un'altra copia del file MP3 sulla fine della stessa. Quella copia viene effettivamente ignorata dal decoder: non è un dato raw buffer, è solo una spuria casuale nel flusso di file, seguendo un file MP3 perfettamente completo.

Quello che devi fare è prima decodificare i dati audio in un AudioBuffer, quindi aggiungere i buffer audio in un nuovo AudioBuffer. Questo richiede un po 'di ristrutturazione del tuo codice.

Che cosa si vuole fare è questo:

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

C'è un gap di riproduzione leggera - questo è perché avete quasi 50 ms di silenzio all'inizio del vostro campione del suono, non a causa di problemi di loop.

Spero che questo aiuti!

+1

Grazie, il tuo commento mi ha aiutato! http://72lions.github.com/PlayingChunkedMP3-WebAudioAPI/ – 72lions

+0

@cwilso È possibile connettere più AudioBufferSourceNodes in uno solo in momenti diversi della riproduzione? –

+0

Bene, puoi semplicemente collegarli alla stessa destinazione. Penso che abbia l'effetto che stai cercando. – cwilso

Problemi correlati