不要使用OfflineContext使用ScriptProcessorNode

时间:2017-11-01 04:15:25

标签: javascript web-audio

ScriptProcessorNodeOfflineContext一起使用。

Chrome Mozilla Firefox 中工作。

不适用于 Edge 25 Safari 10

问题是在处理上下文OfflineContextis时会调用一次事件。

jsfiddle没有BufferSource的示例。

jsfiddle基于 MDN example BufferSource的示例。

console.clear();
var playButton = document.querySelector('.play');
var playButtonOffline = document.querySelector('.play-offline');

var current = 0;
var buffer_size = 4096;
var buffer_length = buffer_size * 10;


var audioCtx = new(window.AudioContext || window.webkitAudioContext)();
var scriptNode = audioCtx.createScriptProcessor(buffer_size, 1, 1);
scriptNode.onaudioprocess = whiteNoise;


function whiteNoise(audioProcessingEvent) {
  console.log('onaudioprocess', current);

  // The output buffer contains the samples that will be modified and played
  var outputBuffer = audioProcessingEvent.outputBuffer;

  // Loop through the output channel
  for (var channel = 0; channel < outputBuffer.numberOfChannels; channel++) {
    var outputData = outputBuffer.getChannelData(channel);
    for (var sample = 0; sample < buffer_size; sample++) {
      // add noise to each output sample
      outputData[sample] += ((Math.random() * 2) - 1);
    }
  }
  current += buffer_size;
  if (current > buffer_length)
    scriptNode.disconnect();
}

playButton.onclick = function() {
  current = 0;
  scriptNode.connect(audioCtx.destination);
}

playButtonOffline.onclick = function() {
  var offlineCtx = new(window.OfflineAudioContext || window.webkitOfflineAudioContext)(1, buffer_length, 48000);
  var scriptNodeOffline = offlineCtx.createScriptProcessor(buffer_size, 1, 1);
  scriptNodeOffline.onaudioprocess = whiteNoise;
  current = 0;
  offlineCtx.oncomplete = function(e) {
    console.log('rendered buffer', e.renderedBuffer.getChannelData(0).filter(f => f != 0).length);
  }
  scriptNodeOffline.connect(offlineCtx.destination);
  offlineCtx.startRendering();
}
<button class="play">
  play
</button>
<button class="play-offline">
  Render offline
</button>

更新

Chrome Firefox 生成相同输出中多次点击Render offline

Safari Edge 生成其他输出中多次点击Render offline

jsfiddle上的示例。

// Create AudioContext and buffer source
console.clear();

var playButton = document.querySelector('.play');
var playButtonOffline = document.querySelector('.play-offline');
var myBuffer = null;

var audioCtx = new(window.AudioContext || window.webkitAudioContext)();
var source = audioCtx.createBufferSource();

// Create a ScriptProcessorNode with a bufferSize of 4096 and a single input and output channel
var scriptNode = audioCtx.createScriptProcessor(4096, 1, 1);

// load in an audio track via XHR and decodeAudioData

function getData() {
  request = new XMLHttpRequest();
  request.open('GET', 'https://s3-ap-northeast-1.amazonaws.com/storage.cowrite.decodeapps.io/Materials/Media/Audio/59f2b85dd3aed-20171027-043853.mp3', true);
  request.responseType = 'arraybuffer';
  request.onload = function() {
    var audioData = request.response;

    audioCtx.decodeAudioData(audioData, function(buffer) {
        myBuffer = buffer;
        source.buffer = myBuffer;
      },
      function(e) {
        "Error with decoding audio data" + e.err
      });
  }
  request.send();
}

function addNoise(audioProcessingEvent) {
  console.log("onaudioprocess")
  // The input buffer is the song we loaded earlier
  var inputBuffer = audioProcessingEvent.inputBuffer;

  // The output buffer contains the samples that will be modified and played
  var outputBuffer = audioProcessingEvent.outputBuffer;

  // Loop through the output channels (in this case there is only one)
  for (var channel = 0; channel < outputBuffer.numberOfChannels; channel++) {
    var inputData = inputBuffer.getChannelData(channel);
    var outputData = outputBuffer.getChannelData(channel);

    // Loop through the 4096 samples
    for (var sample = 0; sample < inputBuffer.length; sample++) {
      // make output equal to the same as the input
      outputData[sample] = inputData[sample];

      // add noise to each output sample
      outputData[sample] += ((Math.random() * 2) - 1) * 0.2;
    }
  }
}

// Give the node a function to process audio events
scriptNode.onaudioprocess = addNoise;

getData();

// wire up play button
playButton.onclick = function() {
  source.connect(scriptNode);
  scriptNode.connect(audioCtx.destination);
  source.start();
}

// When the buffer source stops playing, disconnect everything
source.onended = function() {
  source.disconnect(scriptNode);
  scriptNode.disconnect(audioCtx.destination);
}


// When the buffer source stops playing, disconnect everything


// wire up play button
playButtonOffline.onclick = function() {
  var offlineCtx = new(window.OfflineAudioContext || window.webkitOfflineAudioContext)(2, myBuffer.length, myBuffer.sampleRate);
  var scriptNodeOffline = offlineCtx.createScriptProcessor(4096, 1, 1);
  var sourceOffline = offlineCtx.createBufferSource();
  sourceOffline.buffer = myBuffer;
  sourceOffline.onended = function() {
    console.log('sourceOffline.onended');
    sourceOffline.disconnect(scriptNodeOffline);
    scriptNodeOffline.disconnect(offlineCtx.destination);
  }
  scriptNodeOffline.onaudioprocess = addNoise;
  sourceOffline.connect(scriptNodeOffline);
  scriptNodeOffline.connect(offlineCtx.destination);
  sourceOffline.start();
  offlineCtx.oncomplete = function(e) {
    console.log('renderedBuffer', e.renderedBuffer.getChannelData(0).filter(f => f != 0).length);
    listenRendered(e.renderedBuffer);
  };
  offlineCtx.startRendering();
}

var _audioCtx = new(window.AudioContext || window.webkitAudioContext)();

function listenRendered(buffer) {
  var _source = _audioCtx.createBufferSource();
  _source.buffer = buffer;
  _source.connect(_audioCtx.destination);
  _source.start();
}
<button class="play">
  play
</button>
<button class="play-offline">
  Render offline
</button>

1 个答案:

答案 0 :(得分:1)

这些是Safari和Edge中的错误。 ScriptProcessorNode应该在脱机上下文中正常工作。使用Safari和Edge存档错误。