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.
363 lines
10 KiB
363 lines
10 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 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'; |
|
}
|
|
|