在JavaScripting

时间:2016-11-19 19:16:33

标签: javascript web-audio pitch-shifting

我正在研究用于上传文件的JS音高移位器。

作为我代码的一部分,我使用了这个来源: https://github.com/urtzurd/html-audio

现在我一直坚持出口。所以我可以上传本地存储的文件,然后将它移位,但后来我想导出它,但是找不到办法做到这一点。

我从这里尝试了recorder.js: https://github.com/mattdiamond/Recorderjs 但它似乎只适用于实时录制的文件,我想专门导出上传的文件。

这是我的代码。

var pitchShifter = (function() {
  var audioContext,
    audioSources = [],
    pitchShifterProcessor,
    spectrumAudioAnalyser,
    sonogramAudioAnalyser;
  var validPitchRatio = [0.5, 1.0, 1.5, 2.0],
    pitchRatio = validPitchRatio[1],
    grainSize = 512,
    overlapRatio = 0.50,
    spectrumFFTSize = 128,
    spectrumSmoothing = 0.8,
    sonogramFFTSize = 2048,
    sonogramSmoothing = 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);
  }
  hannWindow = function(length) {
    var window = new Float32Array(length);
    for(var i = 0; i < length; i++) {
      window[i] = 0.5 * (1 - Math.cos(2 * Math.PI * i / (length - 1)));
    }
    return window;
  };
  linearInterpolation = function(a, b, t) {
    return a + (b - a) * t;
  };
  initAudio = function() {
    if(!navigator.webkitGetUserMedia) {
      alert('Your browser does not support the Media Stream API');
    } else {
      navigator.webkitGetUserMedia({
        audio: true,
        video: false
      }, function(stream) {
        audioSources[1] = audioContext.createMediaStreamSource(stream);
      }, function(error) {
        alert('Unable to get the user media');
      });
    }
    spectrumAudioAnalyser = audioContext.createAnalyser();
    spectrumAudioAnalyser.fftSize = spectrumFFTSize;
    spectrumAudioAnalyser.smoothingTimeConstant = spectrumSmoothing;
    sonogramAudioAnalyser = audioContext.createAnalyser();
    sonogramAudioAnalyser.fftSize = sonogramFFTSize;
    sonogramAudioAnalyser.smoothingTimeConstant = sonogramSmoothing;
    var bufferLoader = new BufferLoader(audioContext, ['audio/voice.mp3'], function(bufferList) {
      audioSources[0] = audioContext.createBufferSource();
      audioSources[0].buffer = bufferList[0];
      audioSources[0].loop = false;
      audioSources[0].connect(pitchShifterProcessor);
      audioSources[0].start(0);
    });
    bufferLoader.load();
  };
  initProcessor = function() {
    if(pitchShifterProcessor) {
      pitchShifterProcessor.disconnect();
    }
    if(audioContext.createScriptProcessor) {
      pitchShifterProcessor = audioContext.createScriptProcessor(grainSize, 1, 1);
    } else if(audioContext.createJavaScriptNode) {
      pitchShifterProcessor = audioContext.createJavaScriptNode(grainSize, 1, 1);
    }
    pitchShifterProcessor.buffer = new Float32Array(grainSize * 2);
    pitchShifterProcessor.grainWindow = hannWindow(grainSize);
    pitchShifterProcessor.onaudioprocess = function(event) {
      var inputData = event.inputBuffer.getChannelData(0);
      var outputData = event.outputBuffer.getChannelData(0);
      for(i = 0; i < inputData.length; i++) {
        // Apply the window to the input buffer
        inputData[i] *= this.grainWindow[i];
        // Shift half of the buffer
        this.buffer[i] = this.buffer[i + grainSize];
        // Empty the buffer tail
        this.buffer[i + grainSize] = 0.0;
      }
      // Calculate the pitch shifted grain re-sampling and looping the input
      var grainData = new Float32Array(grainSize * 2);
      for(var i = 0, j = 0.0; i < grainSize; i++, j += pitchRatio) {
        var index = Math.floor(j) % grainSize;
        var a = inputData[index];
        var b = inputData[(index + 1) % grainSize];
        grainData[i] += linearInterpolation(a, b, j % 1.0) * this.grainWindow[i];
      }
      // Copy the grain multiple times overlapping it
      for(i = 0; i < grainSize; i += Math.round(grainSize * (1 - overlapRatio))) {
        for(j = 0; j <= grainSize; j++) {
          this.buffer[i + j] += grainData[j];
        }
      }
      // Output the first half of the buffer
      for(i = 0; i < grainSize; i++) {
        outputData[i] = this.buffer[i];
      }
    };
    pitchShifterProcessor.connect(spectrumAudioAnalyser);
    pitchShifterProcessor.connect(sonogramAudioAnalyser);
    pitchShifterProcessor.connect(audioContext.destination);
  };
  return {
    init: function() {
      if('AudioContext' in window) {
        audioContext = new AudioContext();
      } else {
        alert('Your browser does not support the Web Audio API');
        return;
      }
      initAudio();
      initProcessor();
    }
  }
}());
window.addEventListener("DOMContentLoaded", pitchShifter.init, true);

想听听任何提示。谢谢!

0 个答案:

没有答案