グラフィックイコライザー (サウンド) | エフェクター

WAVE TYPE
(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();

        // Parameter for the instance of OscillatorNode
        var type = oscillator.type;

        // for legacy browsers
        context.createGain = context.createGain || context.createGainNode;

        // Create the instance of GainNode (for master volume)
        var gain = context.createGain();

        // Equalizer

        var NUM_BANDS = 10;
        var peakings  = new Array(NUM_BANDS);

        // Center frequency
        var frequency = 31.25;

        for (var i = 0; i < NUM_BANDS; i++) {
            // Create the instance of BiquadFilterNode
            var peaking = context.createBiquadFilter();

            // Calculate center frequency
            if (i !== 0) {
                frequency *= 2;
            }

            // Set parameters
            peaking.type            = (typeof peaking.type === 'string') ? 'peaking' : 5;
            peaking.frequency.value = frequency;
            peaking.Q.value         = 2;
            peaking.gain.value      = document.getElementById('range-equalizer-' + frequency).valueAsNumber;

            peakings[i] = peaking;
        }

        // Flag for starting or stopping sound
        var isStop = true;

        // for drawing spectrum

        // Create the instance of AnalyserNode
        var analyser = context.createAnalyser();

        analyser.minDecibels = -150;  // Default -100 dB
        analyser.maxDecibels =    0;  // Default  -30 dB

        var canvases = {
            low  : null,
            high : null
        };

        var contexts = {
            low  : null,
            high : null
        };

        canvases.low  = document.querySelectorAll('canvas')[0];
        canvases.high = document.querySelectorAll('canvas')[1];

        contexts.low  = canvases.low.getContext('2d');
        contexts.high = canvases.high.getContext('2d');

        var intervalids = [];

        var drawSpectrum = function(canvas, canvasContext, size, frequency) {
            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 range = analyser.maxDecibels - analyser.minDecibels;  // 70 dB

            // Frequency Resolution
            var fsDivN = context.sampleRate / analyser.fftSize;

            // This value is the number of samples during "frequency" Hz
            var nHz = Math.floor(frequency / fsDivN);

            // Get data for drawing spectrum (dB)
            var spectrums = new Float32Array(size);
            analyser.getFloatFrequencyData(spectrums);

            // Clear previous data
            canvasContext.clearRect(0, 0, canvas.width, canvas.height);

            // Draw spectrum (dB)
            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] - analyser.maxDecibels) / range) * innerHeight) + paddingTop;

                if (i === 0) {
                    canvasContext.moveTo(x, y);
                } else {
                    canvasContext.lineTo(x, y);
                }

                if ((i % nHz) === 0) {
                    var text = '';

                    if (frequency < 1000) {
                        text = (frequency * (i / nHz)) + ' Hz';  // index -> frequency
                    } else {
                        text = (parseInt(frequency / 1000) * (i / nHz)) + ' kHz';  // index -> frequency
                    }

                    // 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      = '12px "Times New Roman"';
                    canvasContext.fillText(text, (x - (canvasContext.measureText(text).width / 2)), (height - 3));
                }
            }

            canvasContext.strokeStyle = 'rgba(0, 0, 255, 1.0)';
            canvasContext.lineWidth   = 4;
            canvasContext.lineCap     = 'round';
            canvasContext.lineJoin    = 'miter';
            canvasContext.stroke();

            // Draw grid and text (Y)
            for (var i = analyser.minDecibels; i <= analyser.maxDecibels; i += 10) {
                var gy = Math.floor(-1 * ((i - analyser.maxDecibels) / 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.fillText((i + ' dB'), 3, gy);
            }
        };

        /*
         * Event Listener
         */

        // Start or Stop sound
        var PIANO_88S = [
                        'A-4', 'A-4h', 'B-4',
                        'C-3', 'C-3h', 'D-3', 'D-3h', 'E-3', 'F-3', 'F-3h', 'G-3', 'G-3h', 'A-3', 'A-3h', 'B-3',
                        'C-2', 'C-2h', 'D-2', 'D-2h', 'E-2', 'F-2', 'F-2h', 'G-2', 'G-2h', 'A-2', 'A-2h', 'B-2',
                        'C-1', 'C-1h', 'D-1', 'D-1h', 'E-1', 'F-1', 'F-1h', 'G-1', 'G-1h', 'A-1', 'A-1h', 'B-1',
                        'C',   'Ch',   'D',   'Dh',   'E',   'F',   'Fh',   'G',   'Gh',   'A',   'Ah',   'B',
                        'C1',  'C1h',  'D1',  'D1h',  'E1',  'F1',  'F1h',  'G1',  'G1h',  'A1',  'A1h',  'B1',
                        'C2',  'C2h',  'D2',  'D2h',  'E2',  'F2',  'F2h',  'G2',  'G2h',  'A2',  'A2h',  'B2',
                        'C3',  'C3h',  'D3',  'D3h',  'E3',  'F3',  'F3h',  'G3',  'G3h',  'A3',  'A3h',  'B3',
                        'C4'
                        ];

        var pianoKeys = Array.prototype.slice.call(document.querySelectorAll('#piano ul li'), 0);

        var convertIndex = function(index) {
            //
            // The 12 equal temparement
            //
            // Min -> A 27.5Hz, Max -> C 4186 Hz
            //
            // Example :
            //    A * 1.059463 -> A# (half up)
            //
            var FREQUENCY_RATIO = Math.pow(2, (1 / 12));  // about 1.059463;
            var MIN_A           = 27.5;

            return (MIN_A * Math.pow(FREQUENCY_RATIO, index));
        };

        pianoKeys.forEach(function(element, index, array) {
            // Start sound
            element.addEventListener(EventWrapper.START, function(event) {
                if (!isStop) {
                    oscillator.stop(0);

                    // Stop drawing spectrum
                    intervalids.forEach(function(intervalid) {
                        window.clearInterval(intervalid);
                    });

                    intervalids = [];
                }

                var pianoIndex = PIANO_88S.indexOf(this.id);
                var frequency  = convertIndex(pianoIndex);

                // Create the instance of OscillatorNode
                oscillator = context.createOscillator();

                // for legacy browsers
                oscillator.start = oscillator.start || oscillator.noteOn;
                oscillator.stop  = oscillator.stop  || oscillator.noteOff;

                // GainNode (Master Volume) -> AnalyserNode (Visualization) -> AudioDestinationNode (Output)
                gain.connect(analyser);
                analyser.connect(context.destination);

                // Clear connection
                oscillator.disconnect(0);

                peakings.forEach(function(peaking) {
                    peaking.disconnect(0);
                });

                if (document.getElementById('toggle-effect').checked) {
                    // Equalizer ON

                    // Connect nodes for effect (Equalizer) sound
                    // OscillatorNode (Input) -> BiquadFilterNode (Peaking Filter x 10) -> GainNode (Master Volume) (-> AnalyserNode (Visualization) -> AudioDestinationNode (Output))
                    oscillator.connect(peakings[0]);

                    peakings.forEach(function(peaking, index) {
                        if (index < (NUM_BANDS - 1)) {
                            peaking.connect(peakings[index + 1]);
                        } else {
                            peaking.connect(gain);
                        }
                    });
                } else {
                    // Equalizer OFF

                    // OscillatorNode (Input) -> GainNode (Master volume) (-> AnalyserNode (Visualization) -> AudioDestinationNode (Output))
                    oscillator.connect(gain);
                }

                // Set parameters
                oscillator.type            = type;
                oscillator.frequency.value = frequency;

                // Start sound
                oscillator.start(0);

                // Start drawing spectrum
                intervalids.push(window.setInterval(function() {
                    drawSpectrum(canvases.low, contexts.low, 16, 62.5);
                }, 20));

                intervalids.push(window.setInterval(function() {
                    drawSpectrum(canvases.high, contexts.high, 750, 1000);
                }, 20));

                isStop = false;
                this.classList.remove('key-off');
                this.classList.add('key-on');
            }, false);

            // Stop sound
            element.addEventListener(EventWrapper.END, function() {
                if (isStop) {
                    return;
                }

                // Stop sound
                oscillator.stop(0);

                // Stop drawing spectrum
                intervalids.forEach(function(intervalid) {
                    window.clearInterval(intervalid);
                });

                intervalids = [];

                isStop = true;
                this.classList.remove('key-on');
                this.classList.add('key-off');
            }, 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);

        // 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);

        // Toggle Effect
        document.getElementById('toggle-effect').addEventListener(EventWrapper.CLICK, function() {
            // Clear connection
            oscillator.disconnect(0);

            peakings.forEach(function(peaking) {
                peaking.disconnect(0);
            });

            if (this.checked) {
                // Equalizer ON

                // Connect nodes for effect (Equalizer) sound
                // OscillatorNode (Input) -> BiquadFilterNode (Peaking Filter x 10) -> GainNode (Master Volume) (-> AnalyserNode (Visualization) -> AudioDestinationNode (Output))
                oscillator.connect(peakings[0]);

                peakings.forEach(function(peaking, index) {
                    if (index < (NUM_BANDS - 1)) {
                        peaking.connect(peakings[index + 1]);
                    } else {
                        peaking.connect(gain);
                    }
                });
            } else {
                // Equalizer OFF

                // OscillatorNode (Input) -> GainNode (Master Volume) (-> AnalyserNode (Visualization) -> AudioDestinationNode (Output))
                oscillator.connect(gain);
            }
        }, false);

        // Control Equalizer
        var equalizers = Array.prototype.slice.call(document.querySelectorAll('div.controllers-2-column dl dd [type="range"]'), 0);

        equalizers.forEach(function(equalizer, index) {
            equalizer.addEventListener('input', function() {
                var peaking = peakings[index];
                var min     = peaking.gain.minValue || -40;
                var max     = peaking.gain.maxValue ||  40;

                if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) {
                    peaking.gain.value = this.valueAsNumber;
                    document.getElementById('output-equalizer-' + this.id.replace('range-equalizer-', '')).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;
})();