コンプレッサー (オーディオ) | エフェクター

LOOP
dB
sec
sec
(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;
})();