【问题标题】:Phonegap mixing audio filesPhonegap 混合音频文件
【发布时间】:2014-09-22 07:49:16
【问题描述】:

我正在使用 Phonegap for Ios 构建一个卡拉 OK 应用程序。

我在 www/assets 文件夹中有可以使用 media.play() 函数播放的音频文件

这允许用户收听背景音轨。当媒体正在播放时,另一个媒体实例正在录制。

录音完成后,我需要将录音文件放在背景音轨上,但我不知道该怎么做。

我认为可能可行的一种方法是使用 WEB Audio API - 我有以下从HTML5 Rocks 获取的代码,它将两个文件加载到 AudioContext 中并允许我同时播放这两个文件。但是,我想做的是将两个缓冲区写入一个 .wav 文件。有什么办法可以将 source1 和 source2 合并到一个新文件中?

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

这个解决方案中可能有一些东西How do I convert an array of audio data into a wav file? 据我所知,它们将两个缓冲区交错并将它们编码为 .wav,但我无法弄清楚它们将它们写入文件的位置(保存新的 wav 文件)有什么想法吗?

下面的答案 - 并没有真正帮助,因为我使用的是 Web Audio Api (javascript) 而不是 IOS

【问题讨论】:

    标签: ios cordova audio html5-audio web-audio-api


    【解决方案1】:

    解决方案是使用offlineAudioContext

    步骤如下: 1. 使用 BufferLoader 将两个文件加载为缓冲区 2. 创建一个离线音频上下文 3.将两个缓冲区连接到OfflineAudioContext 4.启动两个缓冲区 5.使用离线startRendering功能 6.设置offline.oncomplete函数获取renderBuffer的句柄。

    代码如下:

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

    【讨论】:

      【解决方案2】:

      我建议直接混合 PCM。如果您初始化一个与两个轨道的时间范围重叠的缓冲区,则公式是相加的:

      混合(a,b) = a+b - a*b/65535。

      这个公式依赖于无符号的 16 位整数。这是一个例子:

      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];
        }
      }
      

      这是处理签名 16 位音频的一种非常有效的方法。 Go here for the source

      【讨论】:

      • 嗨对不起,我不确定这是否能回答问题。我正在寻找专门从两个缓冲区编写编码 .wav 文件。但是您链接到的代码示例是用本机编写的,我使用的是 Phonegap,所以我仅限于 Javascript - 因此使用 Web Audio。我遇到过其他示例,说明这在 Java 或 C 中是微不足道的,但在 Javascript 中却不是,不幸的是,这就是我工作的环境。再次感谢。
      • 对不起,我花了 6 年才看到这个。 ;-) 在 javascript 中,您可以使用本机数字(双精度/浮点数)进行此计算,并使用 DataView 将它们写为 int16。使用 dataview,编写 wav 标头格式然后再写入数据应该很容易。可以找到header格式的描述here
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-02
      • 1970-01-01
      • 1970-01-01
      • 2015-10-12
      • 2013-05-22
      • 1970-01-01
      相关资源
      最近更新 更多