1/* 2 * Copyright (c) 2014 The Chromium OS Authors. All rights reserved. 3 * Use of this source code is governed by a BSD-style license that can be 4 * found in the LICENSE file. 5 */ 6 7var FFT_SIZE = 2048; 8 9var audioContext; 10var tonegen; 11var recorder; 12var drawContext; 13var audioPlay, audioBuffer; 14var audioSourceType = "sweep"; 15var recordSourceType = "microphone"; 16 17/** 18 * Switches Play/Record tab 19 * @param {string} tab name 20 */ 21function switchTab(tabName) { 22 var canvas_detail = document.getElementsByClassName('canvas_detail'); 23 switch (tabName) { 24 case 'play_tab': 25 document.getElementById('record_tab').setAttribute('class', ''); 26 document.getElementById('record_div').style.display = 'none'; 27 document.getElementById('play_div').style.display = 'block'; 28 for (var i = 0; i < canvas_detail.length; i++) { 29 canvas_detail[i].style.display = "none"; 30 } 31 drawContext.drawBg(); 32 break; 33 case 'record_tab': 34 document.getElementById('play_tab').setAttribute('class', ''); 35 document.getElementById('play_div').style.display = 'none'; 36 document.getElementById('record_div').style.display = 'block'; 37 for (var i = 0; i < canvas_detail.length; i++) { 38 canvas_detail[i].style.display = "block"; 39 } 40 drawContext.drawCanvas(); 41 break; 42 } 43 document.getElementById(tabName).setAttribute('class', 'selected'); 44} 45 46function __log(e, data) { 47 log.innerHTML += "\n" + e + " " + (data || ''); 48} 49 50function startUserMedia(stream) { 51 var input = audioContext.createMediaStreamSource(stream); 52 recorder = new Recorder(input); 53} 54 55window.onload = function init() { 56 setupSourceLayer(audioSourceType); 57 try { 58 // webkit shim 59 window.AudioContext = window.AudioContext || window.webkitAudioContext; 60 navigator.getUserMedia = navigator.getUserMedia || 61 navigator.webkitGetUserMedia; 62 window.URL = window.URL || window.webkitURL; 63 64 audioContext = new AudioContext; 65 } catch (e) { 66 alert('No web audio support in this browser!'); 67 } 68 69 navigator.getUserMedia({audio: true}, startUserMedia, function(e) { 70 alert('No live audio input: ' + e); 71 }); 72 73 /* Initialize global objects */ 74 tonegen = new ToneGen(); 75 audioPlay = new AudioPlay(); 76 77 var canvas = document.getElementById('fr_canvas'); 78 drawContext = new DrawCanvas(canvas, audioContext.sampleRate / 2); 79 drawContext.drawBg(); 80}; 81 82/* For Play tab */ 83 84/** 85 * Sets audio source layer 86 * @param {string} audio source type 87 */ 88function setupSourceLayer(value) { 89 var sourceTone = document.getElementById('source_tone'); 90 var sourceFile = document.getElementById('source_file'); 91 var sweepTone = document.getElementsByClassName('sweep_tone'); 92 audioSourceType = value; 93 switch (value) { 94 case 'sine': 95 for (var i = 0; i < sweepTone.length; i++) { 96 sweepTone[i].style.display = "none"; 97 } 98 document.getElementById('freq_start').value = 1000; 99 document.getElementById('freq_end').value = 1000; 100 sourceTone.style.display = "block"; 101 sourceFile.style.display = "none"; 102 document.getElementById('play_audio').disabled = false; 103 break; 104 case 'sweep': 105 for (var i = 0; i < sweepTone.length; i++) { 106 sweepTone[i].style.display = "block"; 107 } 108 document.getElementById('freq_start').value = 20; 109 document.getElementById('freq_end').value = 12000; 110 sourceTone.style.display = "block"; 111 sourceFile.style.display = "none"; 112 document.getElementById('play_audio').disabled = false; 113 break; 114 case 'file': 115 sourceTone.style.display = "none"; 116 sourceFile.style.display = "block"; 117 document.getElementById('play_audio').disabled = true; 118 break; 119 } 120} 121 122/** 123 * Sets left/right gain 124 */ 125function gainChanged() { 126 var leftGain = document.getElementById('left_gain').value; 127 var rightGain = document.getElementById('right_gain').value; 128 var gainLabel = document.getElementById('gain_label'); 129 gainLabel.innerHTML = 'L(' + leftGain + ') / R(' + rightGain + ')'; 130} 131 132/** 133 * Checks sine tone generator parameters and sets audio buffer 134 */ 135function toneValueCheckSet() { 136 var passed = true; 137 var freqStart = parseInt(document.getElementById('freq_start').value); 138 var freqEnd = parseInt(document.getElementById('freq_end').value); 139 var duration = parseFloat(document.getElementById('tone_sec').value); 140 var leftGain = parseInt(document.getElementById('left_gain').value); 141 var rightGain = parseInt(document.getElementById('right_gain').value); 142 var sweepLog = document.getElementById('sweep_log').checked; 143 144 function isNumber(value, msg) { 145 if (isNaN(value) || value <= 0) { 146 alert(msg); 147 passed = false; 148 } 149 } 150 151 if (audioSourceType == 'sine') { 152 freqEnd = freqStart; 153 } 154 155 isNumber(freqStart, "Start frequency should be a positive number."); 156 isNumber(freqEnd, "Stop frequency should be a positive number."); 157 isNumber(duration, "Duration should be a positive number."); 158 if (freqEnd > audioContext.sampleRate / 2) { 159 alert('Stop frequency is too large.'); 160 passed = false; 161 } 162 if (freqStart < 20) { 163 alert('Start frequency is too small.'); 164 passed = false; 165 } 166 if (passed) { 167 /* Passed value check and generate tone buffer */ 168 tonegen.setFreq(freqStart, freqEnd, sweepLog); 169 tonegen.setDuration(duration); 170 tonegen.setGain(leftGain / 20, rightGain / 20); 171 tonegen.setSampleRate(audioContext.sampleRate); 172 tonegen.genBuffer(); 173 var buffer = tonegen.getBuffer(); 174 audioPlay.setBuffer(buffer, document.getElementById('append_tone').checked); 175 } 176 return passed; 177} 178 179function loadAudioFile() { 180 document.getElementById('audio_file').click(); 181} 182 183/** 184 * Loads audio file from local drive 185 */ 186function changeAudioFile() { 187 function loadAudioDone(filename, buffer) { 188 audioBuffer = buffer; 189 document.getElementById('play_audio').disabled = false; 190 } 191 var input = document.getElementById('audio_file'); 192 document.getElementById('play_audio').disabled = true; 193 audioPlay.loadFile(input.files[0], loadAudioDone); 194 input.value = ''; 195} 196 197/** 198 * Play audio according source type 199 */ 200function playAudioFile() { 201 /** 202 * Callback function to draw frequency response of current buffer 203 */ 204 function getInstantBuffer(leftData, rightData, sampleRate) { 205 drawContext.drawInstantCurve(leftData, rightData, sampleRate); 206 } 207 208 var btn = document.getElementById('play_audio'); 209 var append = document.getElementById('append_tone').checked; 210 if (btn.className == 'btn-off') { 211 switch (audioSourceType) { 212 case 'sine': 213 case 'sweep': 214 if (toneValueCheckSet()) { 215 audioPlay.play(playAudioFile, getInstantBuffer); 216 btn.className = 'btn-on'; 217 } 218 break; 219 case 'file': 220 audioPlay.setBuffer(audioBuffer, append); 221 audioPlay.play(playAudioFile, getInstantBuffer); 222 btn.className = 'btn-on'; 223 break; 224 } 225 } else { 226 audioPlay.stop(); 227 btn.className = 'btn-off'; 228 drawContext.drawBg(); 229 } 230} 231 232/* For Record tab */ 233 234/** 235 * Sets record source type 236 * @param {string} record source type 237 */ 238function setupRecordSource(value) { 239 recordSourceType = value; 240 var autoStop = document.getElementById('auto_stop'); 241 if (value == 'audio') { 242 autoStop.disabled = true; 243 autoStop.checked = false; 244 } else { 245 autoStop.disabled = false; 246 autoStop.checked = true; 247 } 248} 249 250function loadButtonClicked() { 251 document.getElementById('sample_file').click(); 252} 253 254/** 255 * Loads sample file to draw frequency response curve into canvas 256 */ 257function loadSampleFile() { 258 /** 259 * Callback function when file loaded 260 * @param {string} file name 261 * @param {AudioBuffer} file buffer 262 */ 263 function addFileToCanvas(filename, buffer) { 264 var newBuffer = []; 265 for (var i = 0; i < buffer.numberOfChannels; i++) { 266 newBuffer.push(buffer.getChannelData(i)); 267 } 268 drawContext.add(new AudioCurve(newBuffer, filename, buffer.sampleRate)); 269 } 270 var input = document.getElementById('sample_file'); 271 audioPlay.loadFile(input.files[0], addFileToCanvas); 272 input.value = ''; 273} 274 275/** 276 * Starts/Stops record function 277 */ 278function recordButtonClicked() { 279 /** 280 * Callback function to draw frequency response of current recorded buffer 281 */ 282 function getInstantBuffer(leftData, rightData, sampleRate, stop) { 283 drawContext.drawInstantCurve(leftData, rightData, sampleRate); 284 if (stop) 285 recordButtonClicked(); 286 } 287 288 var btn = document.getElementById('record_btn'); 289 if (btn.className == 'btn-off') { 290 var detect = document.getElementById('detect_tone').checked; 291 var autoStop = document.getElementById('auto_stop').checked; 292 var append = document.getElementById('append_tone').checked; 293 if (recordSourceType == 'audio') { 294 switch(audioSourceType) { 295 case 'sine': 296 case 'sweep': 297 if (toneValueCheckSet()) { 298 audioPlay.play(recordButtonClicked); 299 btn.className = 'btn-on'; 300 } 301 break; 302 case 'file': 303 audioPlay.setBuffer(audioBuffer, append); 304 audioPlay.play(recordButtonClicked); 305 btn.className = 'btn-on'; 306 break; 307 } 308 } else { 309 btn.className = 'btn-on'; 310 } 311 recorder.record(getInstantBuffer, detect, autoStop); 312 } else { 313 recorder.stop(); 314 if (recordSourceType == 'audio') { 315 audioPlay.stop(); 316 } 317 // create WAV download link using audio data blob 318 var filename = new Date().toISOString() + '.wav'; 319 buffer = recorder.getBuffer(); 320 drawContext.add(new AudioCurve(buffer, filename, audioContext.sampleRate)); 321 createDownloadLink(filename); 322 recorder.clear(); 323 btn.className = 'btn-off'; 324 } 325} 326 327/** 328 * Creates download link of recorded file 329 * @param {string} file name 330 */ 331function createDownloadLink(filename) { 332 var blob = recorder.exportWAV(); 333 var url = URL.createObjectURL(blob); 334 var table = document.getElementById('record_list'); 335 var au = document.createElement('audio'); 336 au.controls = true; 337 au.src = url; 338 339 var hf = document.createElement('a'); 340 hf.href = url; 341 hf.download = filename; 342 hf.innerHTML = hf.download; 343 344 var tr = table.insertRow(table.rows.length); 345 var td_au = tr.insertCell(0); 346 var td_hf = tr.insertCell(1); 347 td_hf.style = "white-space: nowrap"; 348 td_au.appendChild(au); 349 td_hf.appendChild(hf); 350} 351 352/** 353 * Exports frequency response CVS file of curves on the canvas 354 */ 355function exportCSV() { 356 var hf = document.getElementById('export_csv'); 357 var noctaves = document.getElementById('noctaves').value; 358 content = drawContext.exportCurve(noctaves); 359 var blob = new Blob([content], {type: 'application/octet-stream'}); 360 var url = URL.createObjectURL(blob); 361 hf.href = url; 362 hf.download = 'audio.csv'; 363} 364