Pregunta

Estoy construyendo una aplicación de karaoke usando phonegap para iOS.

Tengo archivos de audio en la carpeta WWW / Activos que puedo reproducir usando la función Media.Play ()

Esto permite al usuario escuchar la pista de respaldo. Mientras que los medios de comunicación están jugando otra instancia de medios, está grabando.

Una vez que la grabación haya finalizado, necesito colocar el archivo de grabación de voz sobre la pista de respaldo y no tengo idea de cómo podría hacer esto.

Un enfoque que pensé que podría trabajar es usar la API de audio web, tengo el siguiente código que tomé de html5 rocks que carga los dos archivos en un audiocontext y me permite reproducir ambos simultáneamente. Sin embargo, lo que me gustaría hacer es escribir los dos búferes en un solo archivo .wav. ¿Hay alguna forma en que pueda combinar la fuente1 y Source2 en un solo archivo nuevo?

var context;
var bufferLoader;

function init() {
    // Fix up prefixing
    window.AudioContext = window.AudioContext || window.webkitAudioContext;
    context = new AudioContext();

    bufferLoader = new BufferLoader(
        context,
        [
            'backingTrack.wav',
            'voice.wav',
        ],
        finishedLoading
    );

    bufferLoader.load();
}

function finishedLoading(bufferList) {
    // Create two sources and play them both together.
    var source1 = context.createBufferSource();
    var source2 = context.createBufferSource();
    source1.buffer = bufferList[0];
    source2.buffer = bufferList[1];

    source1.connect(context.destination);
    source2.connect(context.destination);
    source1.start(0);
    source2.start(0);
}


function BufferLoader(context, urlList, callback) {
    this.context = context;
    this.urlList = urlList;
    this.onload = callback;
    this.bufferList = new Array();
    this.loadCount = 0;
}

BufferLoader.prototype.loadBuffer = function(url, index) {
    // Load buffer asynchronously
    var request = new XMLHttpRequest();
    request.open("GET", url, true);
    request.responseType = "arraybuffer";

    var loader = this;

    request.onload = function() {
        // Asynchronously decode the audio file data in request.response
        loader.context.decodeAudioData(
            request.response,
            function(buffer) {
                if (!buffer) {
                    alert('error decoding file data: ' + url);
                    return;
                }
                loader.bufferList[index] = buffer;
                if (++loader.loadCount == loader.urlList.length)
                    loader.onload(loader.bufferList);
            },
            function(error) {
                console.error('decodeAudioData error', error);
            }
        );
    }

    request.onerror = function() {
        alert('BufferLoader: XHR error');
    }

    request.send();
}

BufferLoader.prototype.load = function() {
    for (var i = 0; i < this.urlList.length; ++i)
        this.loadBuffer(this.urlList[i], i);
}

Puede haber algo en esta solución ¿Cómo convertir una matriz de datos de audio en un archivo WAV? por lo que puedo hacer, están intercalando los dos búferes y codificándolos como un .wav pero no puedo averiguar dónde ¿Los están escribiendo a un archivo (guardando el nuevo archivo WAV) alguna idea?

La respuesta a continuación: realmente no ayuda, ya que estoy usando API de audio web (JavaScript), no iOS

¿Fue útil?

Solución

La solución fue utilizar el OFFLINEAUDIOCTEXT

Los pasos fueron: 1. Cargue los dos archivos como buffers usando el cargador buffer 2. Crea un OffineAudiocontext 3. Conecte los dos búferes al OffineAudiocontext 4. Comience los dos búferes. 5. Utilice la función de inicio de inicio sin conexión 6. Establezca la función OFFFLINE.ONCLETETETE para obtener un asa en el RenderedBuffer.

Aquí está el código:

offline = new webkitOfflineAudioContext(2, voice.buffer.length, 44100);
vocalSource = offline.createBufferSource();
vocalSource.buffer = bufferList[0];
vocalSource.connect(offline.destination);

backing = offline.createBufferSource();
backing.buffer = bufferList[1];
backing.connect(offline.destination);

vocalSource.start(0);
backing.start(0);

offline.oncomplete = function(ev){
    alert(bufferList);
    playBackMix(ev);
    console.log(ev.renderedBuffer);
    sendWaveToPost(ev);
}
offline.startRendering();

Otros consejos

Sugeriría mezclar directamente el PCM.Si inicializa un búfer que se superpone a los marcos de tiempo de ambas pistas, la fórmula es aditiva:

Mezcla (A, B)= A + B - A * B / 65535.

Esta fórmula depende de enteros de 16 bits sin firmar.Aquí hay un ejemplo:

SInt16 *bufferA, SInt16 *bufferB;
NSInteger bufferLength;
SInt16 *outputBuffer;

for ( NSInteger i=0; i<bufferLength; i++ ) {
  if ( bufferA[i] < 0 && bufferB[i] < 0 ) {
    // If both samples are negative, mixed signal must have an amplitude between 
    // the lesser of A and B, and the minimum permissible negative amplitude
    outputBuffer[i] = (bufferA[i] + bufferB[i]) - ((bufferA[i] * bufferB[i])/INT16_MIN);
  } else if ( bufferA[i] > 0 && bufferB[i] > 0 ) {
    // If both samples are positive, mixed signal must have an amplitude between the greater of
    // A and B, and the maximum permissible positive amplitude
    outputBuffer[i] = (bufferA[i] + bufferB[i]) - ((bufferA[i] * bufferB[i])/INT16_MAX);
  } else {
    // If samples are on opposite sides of the 0-crossing, mixed signal should reflect 
    // that samples cancel each other out somewhat
    outputBuffer[i] = bufferA[i] + bufferB[i];
  }
}

Esta puede ser una forma muy efectiva de manejar el audio de 16 bits firmado. Ve aquí para la fuente .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top