(function() { var onDOMContentLoaded = function() { window.AudioContext = window.AudioContext || window.webkitAudioContext; try { // Create the instance of AudioContext var context = new AudioContext(); } catch (error) { window.alert(error.message + ' : Please use Chrome or Safari.'); return; } // Create the instance of OscillatorNode var oscillator = context.createOscillator(); // Parameters for the instance of OscillatorNode var type = oscillator.type; var frequency = oscillator.frequency.value; var detune = oscillator.detune.value; // for legacy browsers context.createGain = context.createGain || context.createGainNode; // Create the instance of GainNode var gain = context.createGain(); // Flag for starting or stopping sound var isStop = true; // for drawing sound wave (spectrum) // Create the instance of AnalyserNode var analyser = context.createAnalyser(); var canvas = document.querySelector('canvas'); var canvasContext = canvas.getContext('2d'); var timerid = null; var interval = document.getElementById('range-draw-interval').valueAsNumber; var drawWave = function() { var width = canvas.width; var height = canvas.height; var paddingTop = 20; var paddingBottom = 20; var paddingLeft = 30; var paddingRight = 30; var innerWidth = width - paddingLeft - paddingRight; var innerHeight = height - paddingTop - paddingBottom; var innerBottom = height - paddingBottom; var middle = (innerHeight / 2) + paddingTop; // Frequency resolution var fsDivN = context.sampleRate / analyser.fftSize; // This value is the number of samples during 500 Hz var n500Hz = Math.floor(500 / fsDivN); // Get data for drawing spectrum var spectrums = new Uint8Array(analyser.frequencyBinCount / 4); analyser.getByteFrequencyData(spectrums); // Clear previous data canvasContext.clearRect(0, 0, width, height); // Draw spectrum canvasContext.beginPath(); for (var i = 0, len = spectrums.length; i < len; i++) { var x = Math.floor((i / len) * innerWidth) + paddingLeft; var y = Math.floor((1 - (spectrums[i] / 255)) * innerHeight) + paddingTop; if (i === 0) { canvasContext.moveTo(x, y); } else { canvasContext.lineTo(x, y); } // 500 Hz ? if ((i % n500Hz) === 0) { var f = Math.floor(500 * (i / n500Hz)); // index -> frequency var text = (f < 1000) ? (f + ' Hz') : ((f / 1000) + ' kHz'); // Draw grid (X) canvasContext.fillStyle = 'rgba(255, 0, 0, 1.0)'; canvasContext.fillRect(x, paddingTop, 1, innerHeight); // Draw text (X) canvasContext.fillStyle = 'rgba(255, 255, 255, 1.0)'; canvasContext.font = '16px "Times New Roman"'; canvasContext.fillText(text, (x - (canvasContext.measureText(text).width / 2)), (height - 3)); } } canvasContext.strokeStyle = 'rgba(0, 0, 255, 1.0)'; canvasContext.lineWidth = 2; canvasContext.lineCap = 'round'; canvasContext.lineJoin = 'miter'; canvasContext.stroke(); // Draw grid (Y) canvasContext.fillStyle = 'rgba(255, 0, 0, 1.0)'; canvasContext.fillRect(paddingLeft, middle, innerWidth, 1); canvasContext.fillRect(paddingLeft, paddingTop, innerWidth, 1); canvasContext.fillRect(paddingLeft, innerBottom, innerWidth, 1); // Draw text (Y) canvasContext.fillStyle = 'rgba(255, 255, 255, 1.0)'; canvasContext.font = '16px "Times New Roman"'; canvasContext.fillText('1.00', 3, paddingTop); canvasContext.fillText('0.50', 3, middle); canvasContext.fillText('0.00', 3, innerBottom); timerid = window.setTimeout(drawWave, interval); }; /* * Event Listener */ // Start or Stop sound document.querySelector('button').addEventListener(EventWrapper.CLICK, function() { if (isStop) { // Create the instance of OscillatorNode oscillator = context.createOscillator(); // for legacy browsers oscillator.start = oscillator.start || oscillator.noteOn; oscillator.stop = oscillator.stop || oscillator.noteOff; // OscillatorNode (Input) -> GainNode (Volume) -> AnalyserNode (Visualization) -> AudioDestinationNode (Output) oscillator.connect(gain) gain.connect(analyser); analyser.connect(context.destination); // Set parameters oscillator.type = type; oscillator.frequency.value = frequency; oscillator.detune.value = detune; // Start sound oscillator.start(0); // Start drawing sound wave drawWave(); isStop = false; this.innerHTML = '<span class="icon-pause"></span>'; } else { // Stop sound oscillator.stop(0); // Stop drawing sound wave if (timerid !== null) { window.clearTimeout(timerid); timerid = null; } isStop = true; this.innerHTML = '<span class="icon-start"></span>'; } }, false); // Control Draw Interval document.getElementById('range-draw-interval').addEventListener('input', function() { interval = this.valueAsNumber; document.getElementById('output-draw-interval').textContent = this.value; }, false); // Control Volume document.getElementById('range-volume').addEventListener('input', function() { var min = gain.gain.minValue || 0; var max = gain.gain.maxValue || 1; if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) { gain.gain.value = this.valueAsNumber; document.getElementById('output-volume').textContent = this.value; } }, false); // Select type document.getElementById('form-wave-type').addEventListener('change', function() { for (var i = 0, len = this.elements['radio-wave-type'].length; i < len; i++) { if (this.elements['radio-wave-type'][i].checked) { oscillator.type = type = (typeof oscillator.type === 'string') ? this.elements['radio-wave-type'][i].value : i; break; } } }, false); // Control frequency document.getElementById('range-frequency').addEventListener('input', function() { var min = oscillator.frequency.minValue || 0; var max = oscillator.frequency.maxValue || 100000; if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) { oscillator.frequency.value = frequency = this.valueAsNumber; document.getElementById('output-frequency').textContent = this.value; } }, false); // Control detune document.getElementById('range-detune').addEventListener('input', function() { var min = oscillator.detune.minValue || -4800; var max = oscillator.detune.maxValue || 4800; if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) { oscillator.detune.value = detune = this.valueAsNumber; document.getElementById('output-detune').textContent = this.value; } }, false); // Select fftSize document.getElementById('select-fft-size').addEventListener('change', function() { switch (parseInt(this.value)) { case 32 : case 64 : case 128 : case 256 : case 512 : case 1024 : case 2048 : analyser.fftSize = this.value; break; default : window.alert('The selected FFT size is invalid.'); break; } }, false); // Control smoothingTimeConstant document.getElementById('range-smoothing-time-constant').addEventListener('input', function() { var min = 0; var max = 1; if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) { analyser.smoothingTimeConstant = this.valueAsNumber; document.getElementById('output-smoothing-time-constant').textContent = this.value; } }, false); }; if ((document.readyState === 'interactive') || (document.readyState === 'complete')) { onDOMContentLoaded(); } else { document.addEventListener('DOMContentLoaded', onDOMContentLoaded, true); } })();
function EventWrapper(){ } (function(){ var click = ''; var start = ''; var move = ''; var end = ''; // Touch Panel ? if (/iPhone|iPad|iPod|Android/.test(navigator.userAgent)) { click = 'click'; start = 'touchstart'; move = 'touchmove'; end = 'touchend'; } else { click = 'click'; start = 'mousedown'; move = 'mousemove'; end = 'mouseup'; } EventWrapper.CLICK = click; EventWrapper.START = start; EventWrapper.MOVE = move; EventWrapper.END = end; })();