(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; } // for the instance of AudioBufferSourceNode var source = null; // for legacy browsers context.createGain = context.createGain || context.createGainNode; // Create the instance of GainNode (for master volume) var gain = context.createGain(); // Compressor // Create the instance of DynamicsCompressorNode var compressor = context.createDynamicsCompressor(); // Initialize parameters for Compressor compressor.threshold.value = document.getElementById('range-compressor-threshold').valueAsNumber; compressor.knee.value = document.getElementById('range-compressor-knee').valueAsNumber; compressor.ratio.value = document.getElementById('range-compressor-ratio').valueAsNumber; compressor.attack.value = document.getElementById('range-compressor-attack').valueAsNumber; compressor.release.value = document.getElementById('range-compressor-release').valueAsNumber; // Display "reduction" property in DynamicsCompressorNode var canvas = document.querySelector('canvas'); var canvasContext = canvas.getContext('2d'); var timerid = null; var draw = function(x, y) { var TOTAL_TIME = 10000; // 10 sec var INTERVAL = 10; // 10 msec var MIN_DECIBEL = -100; // dB var MAX_DECIBEL = 0; // dB var RANGE = MAX_DECIBEL - MIN_DECIBEL; // dB 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 isDrawGrid = true; // Draw reduction (dB) canvasContext.beginPath(); if ((x === 0) || (x > (innerWidth + paddingLeft))) { // Clear previous data canvasContext.clearRect(0, 0, canvas.width, canvas.height); // Move start point if (x === 0) { canvasContext.moveTo(paddingLeft, paddingTop); } else { canvasContext.moveTo(paddingLeft, y); } // Update x x = paddingLeft; } else { // Move start point canvasContext.moveTo(x, y); // Update x x += INTERVAL * (innerWidth / TOTAL_TIME); isDrawGrid = false; } var y = paddingTop; // Compressor ON ? if (document.getElementById('toggle-effect').checked) { if (compressor.reduction.value === undefined) { y = Math.floor(-1 * ((compressor.reduction) / RANGE) * innerHeight) + paddingTop; } else { y = Math.floor(-1 * ((compressor.reduction.value) / RANGE) * innerHeight) + paddingTop; } } canvasContext.lineTo(x, y); canvasContext.strokeStyle = 'rgba(0, 0, 255, 1.0)'; canvasContext.lineWidth = 3; canvasContext.lineCap = 'round'; canvasContext.lineJoin = 'miter'; canvasContext.stroke(); if (isDrawGrid) { // Draw grid and text (X) every 1000 msec (1 sec) for (var i = 0; i <= TOTAL_TIME; i += INTERVAL) { if ((i % 1000) !== 0) { continue; } var gx = Math.floor(i * (innerWidth / TOTAL_TIME)) + paddingLeft; var text = i + ' msec'; // Draw grid (X) canvasContext.fillStyle = 'rgba(255, 0, 0, 1.0)'; canvasContext.fillRect(gx, paddingTop, 1, innerHeight); // Draw text (X) canvasContext.fillStyle = 'rgba(255, 255, 255, 1.0)'; canvasContext.font = '12px "Times New Roman"'; canvasContext.textAlign = 'center'; canvasContext.fillText(text, gx, (height - 3)); } // Draw grid and text (Y) for (var i = MIN_DECIBEL; i <= MAX_DECIBEL; i += 10) { var gy = Math.floor(-1 * ((i - MAX_DECIBEL) / RANGE) * innerHeight) + paddingTop; // Draw grid (Y) canvasContext.fillStyle = 'rgba(255, 0, 0, 1.0)'; canvasContext.fillRect(paddingLeft, gy, innerWidth, 1); // Draw text (Y) canvasContext.fillStyle = 'rgba(255, 255, 255, 1.0)'; canvasContext.font = '12px "Times New Roman"'; canvasContext.textAlign = 'left'; canvasContext.fillText((i + ' dB'), 3, gy); } } timerid = window.setTimeout(function() { draw(x, y); }, INTERVAL); }; // Trigger 'ended' event var trigger = function() { var event = document.createEvent('Event'); event.initEvent('ended', true, true); if (source instanceof AudioBufferSourceNode) { source.dispatchEvent(event); } }; // This funciton is executed after getting ArrayBuffer of audio data var startAudio = function(arrayBuffer) { // The 2nd argument for decodeAudioData var successCallback = function(audioBuffer) { // The 1st argument (audioBuffer) is the instance of AudioBuffer // If there is previous AudioBufferSourceNode, program stops previous audio if ((source instanceof AudioBufferSourceNode) && (source.buffer instanceof AudioBuffer)) { // Execute onended event handler trigger(); source = null; } // Create the instance of AudioBufferSourceNode source = context.createBufferSource(); // for legacy browsers source.start = source.start || source.noteOn; source.stop = source.stop || source.noteOff; // Set the instance of AudioBuffer source.buffer = audioBuffer; // Set parameters source.playbackRate.value = document.getElementById('range-playback-rate').valueAsNumber; source.loop = document.querySelector('[type="checkbox"]').checked; // GainNode (Master Volume) -> AudioDestinationNode (Output); gain.connect(context.destination); // Clear connection source.disconnect(0); compressor.disconnect(0); if (document.getElementById('toggle-effect').checked) { // Compressor ON // Connect nodes for effect (Compressor) sound // AudioBufferSourceNode (Input) -> DynamicsCompressorNode (Compressor) -> GainNode (Master Volume) (-> AudioDestinationNode (Output)) source.connect(compressor); compressor.connect(gain); } else { // Compressor OFF // AudioBufferSourceNode (Input) -> GainNode (Master Volume) (-> AudioDestinationNode (Output)) source.connect(gain); } // Start audio source.start(0); // Start drawing "reduction" draw(0, 0); // Set Callback source.onended = function(event) { // Remove event handler source.onended = null; document.onkeydown = null; // Stop audio source.stop(0); // Stop previous drawing if (timerid !== null) { window.clearTimeout(timerid); timerid = null; } console.log('STOP by "on' + event.type + '" event handler !!'); // Audio is not started !! // It is necessary to create the instance of AudioBufferSourceNode again // Cannot replay // source.start(0); }; // Stop audio document.onkeydown = function(event) { // Space ? if (event.keyCode !== 32) { return; } // Execute onended event handler trigger(); return false; }; }; // The 3rd argument for decodeAudioData var errorCallback = function(error) { if (error instanceof Error) { window.alert(error.message); } else { window.alert('Error : "decodeAudioData" method.'); } }; // Create the instance of AudioBuffer (Asynchronously) context.decodeAudioData(arrayBuffer, successCallback, errorCallback); }; /* * File Uploader */ document.getElementById('file-upload-audio').addEventListener('change', function(event) { var uploader = this; var progressArea = document.getElementById('progress-file-upload-audio'); // Get the instance of File (extends Blob) var file = event.target.files[0]; if (!(file instanceof File)) { window.alert('Please upload file.'); } else if (file.type.indexOf('audio') === -1) { window.alert('Please upload audio file.'); } else { // Create the instance of FileReader var reader = new FileReader(); reader.onprogress = function(event) { if (event.lengthComputable && (event.total > 0)) { var rate = Math.floor((event.loaded / event.total) * 100); progressArea.textContent = rate + ' %'; } }; reader.onerror = function() { window.alert('FileReader Error : Error code is ' + reader.error.code); uploader.value = ''; }; // Success read reader.onload = function() { var arrayBuffer = reader.result; // Get ArrayBuffer startAudio(arrayBuffer); uploader.value = ''; progressArea.textContent = file.name; }; // Read the instance of File reader.readAsArrayBuffer(file); } }, false); // Control Master 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); // Control playbackRate document.getElementById('range-playback-rate').addEventListener('input', function() { if (source instanceof AudioBufferSourceNode) { var min = source.playbackRate.minValue || 0; var max = source.playbackRate.maxValue || 1024; if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) { source.playbackRate.value = this.valueAsNumber; } } document.getElementById('output-playback-rate').textContent = this.value; }, false); // Toggle loop document.querySelector('[type="checkbox"]').addEventListener(EventWrapper.CLICK, function() { if (source instanceof AudioBufferSourceNode) { source.loop = this.checked; } }, false); // Toggle Effect document.getElementById('toggle-effect').addEventListener(EventWrapper.CLICK, function() { if (!(source instanceof AudioBufferSourceNode)) { return; } // Clear connection source.disconnect(0); compressor.disconnect(0); if (this.checked) { // Compressor ON // Connect nodes for effect (Compressor) sound // AudioBufferSourceNode (Input) -> DynamicsCompressorNode (Compressor) -> GainNode (Master Volume) (-> AudioDestinationNode (Output)) source.connect(compressor); compressor.connect(gain); } else { // Compressor OFF // AudioBufferSourceNode (Input) -> GainNode (Master Volume) (-> AudioDestinationNode (Output)) source.connect(gain); } }, false); // Control threshold document.getElementById('range-compressor-threshold').addEventListener('input', function() { var min = compressor.threshold.minValue || -100; var max = compressor.threshold.maxValue || 0; if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) { compressor.threshold.value = this.valueAsNumber; document.getElementById('output-compressor-threshold').textContent = this.value; } }, false); // Control knee document.getElementById('range-compressor-knee').addEventListener('input', function() { var min = compressor.knee.minValue || 0; var max = compressor.knee.maxValue || 40; if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) { compressor.knee.value = this.valueAsNumber; document.getElementById('output-compressor-knee').textContent = this.value; } }, false); // Control ratio document.getElementById('range-compressor-ratio').addEventListener('input', function() { var min = compressor.ratio.minValue || 1; var max = compressor.ratio.maxValue || 20; if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) { compressor.ratio.value = this.valueAsNumber; document.getElementById('output-compressor-ratio').textContent = this.value; } }, false); // Control attack document.getElementById('range-compressor-attack').addEventListener('input', function() { var min = compressor.attack.minValue || 0; var max = compressor.attack.maxValue || 1; if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) { compressor.attack.value = this.valueAsNumber; document.getElementById('output-compressor-attack').textContent = this.value; } }, false); // Control release document.getElementById('range-compressor-release').addEventListener('input', function() { var min = compressor.release.minValue || 0.01; var max = compressor.release.maxValue || 1; if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) { compressor.release.value = this.valueAsNumber; document.getElementById('output-compressor-release').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; })();