You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
228 lines
6.1 KiB
228 lines
6.1 KiB
/*
|
|
* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
var ToneGen = function() {
|
|
/**
|
|
* Initializes tone generator.
|
|
*/
|
|
this.init = function() {
|
|
this.audioContext = new AudioContext();
|
|
}
|
|
|
|
/**
|
|
* Sets sample rate
|
|
* @param {int} sample rate
|
|
*/
|
|
this.setSampleRate = function(sampleRate) {
|
|
this.sampleRate = sampleRate;
|
|
}
|
|
|
|
/**
|
|
* Sets start/end frequencies and logarithmic sweep
|
|
* @param {int} start frequency
|
|
* @param {int} end frequency
|
|
* @param {boolean} logarithmic sweep or not
|
|
*/
|
|
this.setFreq = function(freqStart, freqEnd, sweepLog) {
|
|
this.freqStart = freqStart;
|
|
this.freqEnd = freqEnd;
|
|
this.sweepLog = sweepLog;
|
|
}
|
|
|
|
/**
|
|
* Sets tone duration
|
|
* @param {float} duration in seconds
|
|
*/
|
|
this.setDuration = function(duration) {
|
|
this.duration = parseFloat(duration);
|
|
}
|
|
|
|
/**
|
|
* Sets left and right gain value
|
|
* @param {float} left gain between 0 and 1
|
|
* @param {float} right gain between 0 and 1
|
|
*/
|
|
this.setGain = function(leftGain, rightGain) {
|
|
this.leftGain = parseFloat(leftGain);
|
|
this.rightGain = parseFloat(rightGain);
|
|
}
|
|
|
|
/**
|
|
* Generates sine tone buffer
|
|
*/
|
|
this.genBuffer = function() {
|
|
this.buffer = this.audioContext.createBuffer(2,
|
|
this.sampleRate * this.duration, this.sampleRate);
|
|
var leftChannel = this.buffer.getChannelData(0);
|
|
var rightChannel = this.buffer.getChannelData(1);
|
|
var phi;
|
|
var k = this.freqEnd / this.freqStart;
|
|
var beta = this.duration / Math.log(k);
|
|
for (var i = 0; i < leftChannel.length; i++) {
|
|
if (this.sweepLog) {
|
|
phi = 2 * Math.PI * this.freqStart * beta *
|
|
(Math.pow(k, i / leftChannel.length) - 1.0);
|
|
} else {
|
|
var f = this.freqStart + (this.freqEnd - this.freqStart) *
|
|
i / leftChannel.length / 2;
|
|
phi = f * 2 * Math.PI * i / this.sampleRate;
|
|
}
|
|
leftChannel[i] = this.leftGain * Math.sin(phi);
|
|
rightChannel[i] = this.rightGain * Math.sin(phi);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns generated sine tone buffer
|
|
* @return {AudioBuffer} audio buffer
|
|
*/
|
|
this.getBuffer = function() {
|
|
return this.buffer;
|
|
}
|
|
|
|
/**
|
|
* Returns append buffer
|
|
* @return {AudioBuffer} append audio buffer
|
|
*/
|
|
this.getAppendTone = function(sampleRate) {
|
|
var tone_freq = 1000, duration = 0.5;
|
|
this.setFreq(tone_freq, tone_freq, false);
|
|
this.setDuration(duration);
|
|
this.setGain(1, 1);
|
|
this.setSampleRate(sampleRate);
|
|
this.genBuffer();
|
|
return this.getBuffer();
|
|
}
|
|
|
|
this.init();
|
|
}
|
|
|
|
window.ToneGen = ToneGen;
|
|
|
|
var AudioPlay = function() {
|
|
var playCallback = null;
|
|
var sampleRate;
|
|
var playing = false;
|
|
|
|
/**
|
|
* Initializes audio play object
|
|
*/
|
|
this.init = function() {
|
|
this.audioContext = new AudioContext();
|
|
this.genChannel();
|
|
this.buffer = null;
|
|
sampleRate = this.audioContext.sampleRate;
|
|
}
|
|
|
|
/**
|
|
* Loads audio file
|
|
* @param {blob} audio file
|
|
* @param {function} callback function when file loaded
|
|
*/
|
|
this.loadFile = function(file_blob, done_cb) {
|
|
if (file_blob) {
|
|
var audioContext = this.audioContext;
|
|
reader = new FileReader();
|
|
reader.onloadend = function(e) {
|
|
audioContext.decodeAudioData(e.target.result,
|
|
function(buffer) {
|
|
done_cb(file_blob.name, buffer);
|
|
});
|
|
};
|
|
reader.readAsArrayBuffer(file_blob);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets audio path
|
|
*/
|
|
this.genChannel = function() {
|
|
this.node = (this.audioContext.createScriptProcessor ||
|
|
this.audioContext.createJavaScriptNode).call(
|
|
this.audioContext, 4096, 2, 2);
|
|
this.splitter = this.audioContext.createChannelSplitter(2);
|
|
this.merger = this.audioContext.createChannelMerger(2);
|
|
this.node.connect(this.splitter);
|
|
this.splitter.connect(this.merger, 0, 0);
|
|
this.splitter.connect(this.merger, 1, 1);
|
|
this.merger.connect(this.audioContext.destination);
|
|
|
|
this.node.onaudioprocess = function(e) {
|
|
for (var i = 0; i < e.inputBuffer.numberOfChannels; i++) {
|
|
e.outputBuffer.getChannelData(i).set(
|
|
e.inputBuffer.getChannelData(i), 0);
|
|
}
|
|
if (!playing) return;
|
|
if (playCallback) {
|
|
var tmpLeft = e.inputBuffer.getChannelData(0).subarray(
|
|
-FFT_SIZE-1, -1);
|
|
var tmpRight = e.inputBuffer.getChannelData(1).subarray(
|
|
-FFT_SIZE-1, -1);
|
|
playCallback(tmpLeft, tmpRight, sampleRate);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Plays audio
|
|
* @param {function} callback function when audio end
|
|
* @param {function} callback function to get current buffer
|
|
*/
|
|
this.play = function(done_cb, play_cb) {
|
|
playCallback = play_cb;
|
|
this.source = this.audioContext.createBufferSource();
|
|
this.source.buffer = this.buffer;
|
|
this.source.onended = function(e) {
|
|
playing = false;
|
|
this.disconnect();
|
|
if (done_cb) {
|
|
done_cb();
|
|
}
|
|
}
|
|
this.source.connect(this.node);
|
|
this.source.start(0);
|
|
playing = true;
|
|
}
|
|
|
|
/**
|
|
* Stops audio
|
|
*/
|
|
this.stop = function() {
|
|
playing = false;
|
|
this.source.stop();
|
|
this.source.disconnect();
|
|
}
|
|
|
|
/**
|
|
* Sets audio buffer
|
|
* @param {AudioBuffer} audio buffer
|
|
* @param {boolean} append tone or not
|
|
*/
|
|
this.setBuffer = function(buffer, append) {
|
|
if (append) {
|
|
function copyBuffer(src, dest, offset) {
|
|
for (var i = 0; i < dest.numberOfChannels; i++) {
|
|
dest.getChannelData(i).set(src.getChannelData(i), offset);
|
|
}
|
|
}
|
|
var appendTone = tonegen.getAppendTone(buffer.sampleRate);
|
|
var bufferLength = appendTone.length * 2 + buffer.length;
|
|
var newBuffer = this.audioContext.createBuffer(buffer.numberOfChannels,
|
|
bufferLength, buffer.sampleRate);
|
|
copyBuffer(appendTone, newBuffer, 0);
|
|
copyBuffer(buffer, newBuffer, appendTone.length);
|
|
copyBuffer(appendTone, newBuffer, appendTone.length + buffer.length);
|
|
this.buffer = newBuffer;
|
|
} else {
|
|
this.buffer = buffer;
|
|
}
|
|
}
|
|
|
|
this.init();
|
|
}
|
|
|
|
window.AudioPlay = AudioPlay;
|