/* * 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'; }