我正在研究用于上传文件的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);
想听听任何提示。谢谢!