blob: 86974e7351596985c9586f54713ea6b3538edc00 [file] [log] [blame]
/*
* 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 FFT_SIZE = 2048;
var audioContext;
var tonegen;
var recorder;
var drawContext;
var audioPlay, audioBuffer;
var audioSourceType = "sweep";
var recordSourceType = "microphone";
/**
* Switches Play/Record tab
* @param {string} tab name
*/
function switchTab(tabName) {
var canvas_detail = document.getElementsByClassName('canvas_detail');
switch (tabName) {
case 'play_tab':
document.getElementById('record_tab').setAttribute('class', '');
document.getElementById('record_div').style.display = 'none';
document.getElementById('play_div').style.display = 'block';
for (var i = 0; i < canvas_detail.length; i++) {
canvas_detail[i].style.display = "none";
}
drawContext.drawBg();
break;
case 'record_tab':
document.getElementById('play_tab').setAttribute('class', '');
document.getElementById('play_div').style.display = 'none';
document.getElementById('record_div').style.display = 'block';
for (var i = 0; i < canvas_detail.length; i++) {
canvas_detail[i].style.display = "block";
}
drawContext.drawCanvas();
break;
}
document.getElementById(tabName).setAttribute('class', 'selected');
}
function __log(e, data) {
log.innerHTML += "\n" + e + " " + (data || '');
}
function startUserMedia(stream) {
var input = audioContext.createMediaStreamSource(stream);
recorder = new Recorder(input);
}
window.onload = function init() {
setupSourceLayer(audioSourceType);
try {
// webkit shim
window.AudioContext = window.AudioContext || window.webkitAudioContext;
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia;
window.URL = window.URL || window.webkitURL;
audioContext = new AudioContext;
} catch (e) {
alert('No web audio support in this browser!');
}
navigator.getUserMedia({audio: true}, startUserMedia, function(e) {
alert('No live audio input: ' + e);
});
/* Initialize global objects */
tonegen = new ToneGen();
audioPlay = new AudioPlay();
var canvas = document.getElementById('fr_canvas');
drawContext = new DrawCanvas(canvas, audioContext.sampleRate / 2);
drawContext.drawBg();
};
/* For Play tab */
/**
* Sets audio source layer
* @param {string} audio source type
*/
function setupSourceLayer(value) {
var sourceTone = document.getElementById('source_tone');
var sourceFile = document.getElementById('source_file');
var sweepTone = document.getElementsByClassName('sweep_tone');
audioSourceType = value;
switch (value) {
case 'sine':
for (var i = 0; i < sweepTone.length; i++) {
sweepTone[i].style.display = "none";
}
document.getElementById('freq_start').value = 1000;
document.getElementById('freq_end').value = 1000;
sourceTone.style.display = "block";
sourceFile.style.display = "none";
document.getElementById('play_audio').disabled = false;
break;
case 'sweep':
for (var i = 0; i < sweepTone.length; i++) {
sweepTone[i].style.display = "block";
}
document.getElementById('freq_start').value = 20;
document.getElementById('freq_end').value = 12000;
sourceTone.style.display = "block";
sourceFile.style.display = "none";
document.getElementById('play_audio').disabled = false;
break;
case 'file':
sourceTone.style.display = "none";
sourceFile.style.display = "block";
document.getElementById('play_audio').disabled = true;
break;
}
}
/**
* Sets left/right gain
*/
function gainChanged() {
var leftGain = document.getElementById('left_gain').value;
var rightGain = document.getElementById('right_gain').value;
var gainLabel = document.getElementById('gain_label');
gainLabel.innerHTML = 'L(' + leftGain + ') / R(' + rightGain + ')';
}
/**
* Checks sine tone generator parameters and sets audio buffer
*/
function toneValueCheckSet() {
var passed = true;
var freqStart = parseInt(document.getElementById('freq_start').value);
var freqEnd = parseInt(document.getElementById('freq_end').value);
var duration = parseFloat(document.getElementById('tone_sec').value);
var leftGain = parseInt(document.getElementById('left_gain').value);
var rightGain = parseInt(document.getElementById('right_gain').value);
var sweepLog = document.getElementById('sweep_log').checked;
function isNumber(value, msg) {
if (isNaN(value) || value <= 0) {
alert(msg);
passed = false;
}
}
if (audioSourceType == 'sine') {
freqEnd = freqStart;
}
isNumber(freqStart, "Start frequency should be a positive number.");
isNumber(freqEnd, "Stop frequency should be a positive number.");
isNumber(duration, "Duration should be a positive number.");
if (freqEnd > audioContext.sampleRate / 2) {
alert('Stop frequency is too large.');
passed = false;
}
if (freqStart < 20) {
alert('Start frequency is too small.');
passed = false;
}
if (passed) {
/* Passed value check and generate tone buffer */
tonegen.setFreq(freqStart, freqEnd, sweepLog);
tonegen.setDuration(duration);
tonegen.setGain(leftGain / 20, rightGain / 20);
tonegen.setSampleRate(audioContext.sampleRate);
tonegen.genBuffer();
var buffer = tonegen.getBuffer();
audioPlay.setBuffer(buffer, document.getElementById('append_tone').checked);
}
return passed;
}
function loadAudioFile() {
document.getElementById('audio_file').click();
}
/**
* Loads audio file from local drive
*/
function changeAudioFile() {
function loadAudioDone(filename, buffer) {
audioBuffer = buffer;
document.getElementById('play_audio').disabled = false;
}
var input = document.getElementById('audio_file');
document.getElementById('play_audio').disabled = true;
audioPlay.loadFile(input.files[0], loadAudioDone);
input.value = '';
}
/**
* Play audio according source type
*/
function playAudioFile() {
/**
* Callback function to draw frequency response of current buffer
*/
function getInstantBuffer(leftData, rightData, sampleRate) {
drawContext.drawInstantCurve(leftData, rightData, sampleRate);
}
var btn = document.getElementById('play_audio');
var append = document.getElementById('append_tone').checked;
if (btn.className == 'btn-off') {
switch (audioSourceType) {
case 'sine':
case 'sweep':
if (toneValueCheckSet()) {
audioPlay.play(playAudioFile, getInstantBuffer);
btn.className = 'btn-on';
}
break;
case 'file':
audioPlay.setBuffer(audioBuffer, append);
audioPlay.play(playAudioFile, getInstantBuffer);
btn.className = 'btn-on';
break;
}
} else {
audioPlay.stop();
btn.className = 'btn-off';
drawContext.drawBg();
}
}
/* For Record tab */
/**
* Sets record source type
* @param {string} record source type
*/
function setupRecordSource(value) {
recordSourceType = value;
var autoStop = document.getElementById('auto_stop');
if (value == 'audio') {
autoStop.disabled = true;
autoStop.checked = false;
} else {
autoStop.disabled = false;
autoStop.checked = true;
}
}
function loadButtonClicked() {
document.getElementById('sample_file').click();
}
/**
* Loads sample file to draw frequency response curve into canvas
*/
function loadSampleFile() {
/**
* Callback function when file loaded
* @param {string} file name
* @param {AudioBuffer} file buffer
*/
function addFileToCanvas(filename, buffer) {
var newBuffer = [];
for (var i = 0; i < buffer.numberOfChannels; i++) {
newBuffer.push(buffer.getChannelData(i));
}
drawContext.add(new AudioCurve(newBuffer, filename, buffer.sampleRate));
}
var input = document.getElementById('sample_file');
audioPlay.loadFile(input.files[0], addFileToCanvas);
input.value = '';
}
/**
* Starts/Stops record function
*/
function recordButtonClicked() {
/**
* Callback function to draw frequency response of current recorded buffer
*/
function getInstantBuffer(leftData, rightData, sampleRate, stop) {
drawContext.drawInstantCurve(leftData, rightData, sampleRate);
if (stop)
recordButtonClicked();
}
var btn = document.getElementById('record_btn');
if (btn.className == 'btn-off') {
var detect = document.getElementById('detect_tone').checked;
var autoStop = document.getElementById('auto_stop').checked;
var append = document.getElementById('append_tone').checked;
if (recordSourceType == 'audio') {
switch(audioSourceType) {
case 'sine':
case 'sweep':
if (toneValueCheckSet()) {
audioPlay.play(recordButtonClicked);
btn.className = 'btn-on';
}
break;
case 'file':
audioPlay.setBuffer(audioBuffer, append);
audioPlay.play(recordButtonClicked);
btn.className = 'btn-on';
break;
}
} else {
btn.className = 'btn-on';
}
recorder.record(getInstantBuffer, detect, autoStop);
} else {
recorder.stop();
if (recordSourceType == 'audio') {
audioPlay.stop();
}
// create WAV download link using audio data blob
var filename = new Date().toISOString() + '.wav';
buffer = recorder.getBuffer();
drawContext.add(new AudioCurve(buffer, filename, audioContext.sampleRate));
createDownloadLink(filename);
recorder.clear();
btn.className = 'btn-off';
}
}
/**
* Creates download link of recorded file
* @param {string} file name
*/
function createDownloadLink(filename) {
var blob = recorder.exportWAV();
var url = URL.createObjectURL(blob);
var table = document.getElementById('record_list');
var au = document.createElement('audio');
au.controls = true;
au.src = url;
var hf = document.createElement('a');
hf.href = url;
hf.download = filename;
hf.innerHTML = hf.download;
var tr = table.insertRow(table.rows.length);
var td_au = tr.insertCell(0);
var td_hf = tr.insertCell(1);
td_hf.style = "white-space: nowrap";
td_au.appendChild(au);
td_hf.appendChild(hf);
}
/**
* Exports frequency response CVS file of curves on the canvas
*/
function exportCSV() {
var hf = document.getElementById('export_csv');
var noctaves = document.getElementById('noctaves').value;
content = drawContext.exportCurve(noctaves);
var blob = new Blob([content], {type: 'application/octet-stream'});
var url = URL.createObjectURL(blob);
hf.href = url;
hf.download = 'audio.csv';
}