リバーブ (オーディオ) | エフェクター

LOOP
ConvolverNode
ConvolverNode
PropertyValuehasOwnProperty
(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;
        }

        var displayProperties = function(node, tableid, caption) {
            var html = '<caption>' + caption + '</caption>';

            html += '<thead>';
            html += '<tr>';
            html += '<th scope="col">Property</th>';
            html += '<th scope="col">Value</th>';
            html += '<th scope="col">hasOwnProperty</th>';
            html += '</tr>';
            html += '</thead>';

            html += '<tbody>';

            for (var key in node) {
                html += '<tr>';
                html += '<td>' + key + '</td>';
                html += '<td>' + node[key] + '</td>';
                html += '<td>' + node.hasOwnProperty(key) + '</td>';
                html += '</tr>';
            }

            html += '</tbody>';

            document.getElementById(tableid).innerHTML = html;
            document.getElementById(tableid).parentNode.previousElementSibling.style.display = 'block';
        };

        var source    = null;  // for the instance of AudioBufferSourceNode
        var gain      = null;  // for the instance of GainNode (Master Volume)
        var convolver = null;  // for the instance of ConvolverNode (Reverb)
        var dry       = null;  // for the instance of ConvolverNode (Dry)
        var wet       = null;  // for the instance of ConvolverNode (Wet)

        // This function is executed after loading all of the impluse responses
        var onloadCallback = function(reverbs) {

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

            // Create the instance of GainNode (for Master Volume)
            gain = context.createGain();

            // Reverb

            // Create the instance of ConvolverNode
            convolver = context.createConvolver();

            // Create the instance of GainNode (for Reverb)
            dry = context.createGain();
            wet = context.createGain();

            // Initialize parameters for Reverb
            convolver.buffer = null;
            dry.gain.value   = document.getElementById('range-reverb-dry').valueAsNumber;
            wet.gain.value   = document.getElementById('range-reverb-wet').valueAsNumber;

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

                    // Connect nodes for original audio
                    // AudioBufferSourceNode (Input) -> GainNode (Dry) -> GainNode (Master Volume) (-> AudioDestinationNode (Output))
                    source.connect(dry);
                    dry.connect(gain);

                    // Connect nodes for effect (Reverb) sound
                    // AudioBufferSourceNode (Input) -> ConvolverNode (Reverb) -> GainNode (Wet) -> GainNode (Master Volume) (-> AudioDestinationNode (Output))
                    source.connect(convolver);
                    convolver.connect(wet);
                    wet.connect(gain);

                    // Start audio
                    source.start(0);

                    // Set Callback
                    source.onended = function(event) {
                        // Remove event handler
                        source.onended     = null;
                        document.onkeydown = null;

                        // Stop audio
                        source.stop(0);

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

            // Select Reverb type
            document.getElementById('select-reverb-type').addEventListener('change', function() {
                var reverbType = parseInt(this.value);

                if (source instanceof AudioBufferSourceNode) {
                    // Clear connection
                    source.disconnect(0);
                    convolver.disconnect(0);
                    dry.disconnect(0);
                    wet.disconnect(0);

                    if (reverbType === 0) {
                        // Reverb OFF
                        convolver.buffer = null;

                        // AudioBufferSourceNode (Input) -> GainNode (Master Volume) (-> AudioDestinationNode (Output))
                        source.connect(gain);
                    } else {
                        // Revreb ON
                        convolver.buffer = reverbs[reverbType - 1];

                        // Connect nodes for original audio
                        // AudioBufferSourceNode (Input) -> GainNode (Dry) -> GainNode (Master Volume) (-> AudioDestinationNode (Output))
                        source.connect(dry);
                        dry.connect(gain);

                        // Connect nodes for effect (Reverb) sound
                        // AudioBufferSourceNode (Input) -> ConvolverNode (Reverb) -> GainNode (Wet) -> GainNode (Master Volume) (-> AudioDestinationNode (Output))
                        source.connect(convolver);
                        convolver.connect(wet);
                        wet.connect(gain);
                    }
                } else {
                    if (reverbType === 0) {
                        // Reverb OFF
                        convolver.buffer = null;
                    } else {
                        // Revreb ON
                        convolver.buffer = reverbs[reverbType - 1];
                    }
                }

                displayProperties(convolver, 'convolvernode-properties', 'ConvolverNode');
            }, false);

            // Control Reverb Dry
            document.getElementById('range-reverb-dry').addEventListener('input', function() {
                var min = dry.gain.minValue || 0;
                var max = dry.gain.maxValue || 1;

                if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) {
                    dry.gain.value = this.valueAsNumber;
                    document.getElementById('output-reverb-dry').textContent = this.value;
                }
            }, false);

            // Control Reverb Wet
            document.getElementById('range-reverb-wet').addEventListener('input', function() {
                var min = wet.gain.minValue || 0;
                var max = wet.gain.maxValue || 1;

                if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) {
                    wet.gain.value = this.valueAsNumber;
                    document.getElementById('output-reverb-wet').textContent = this.value;
                }
            }, false);

            /*
             * Display properties
             */

            displayProperties(convolver, 'convolvernode-properties', 'ConvolverNode');
        };

        // Load impulse responses
        var base = './impulse-responses/';
        var urls = [
            (base + 's1_r1_b.wav'),
            (base + 's1_r2_b.wav'),
            (base + 's1_r3_b.wav'),
            (base + 's1_r4_b.wav'),
            (base + 's2_r1_b.wav'),
            (base + 's2_r2_b.wav'),
            (base + 's2_r3_b.wav'),
            (base + 's2_r4_b.wav'),
            (base + 's3_r1_b.wav'),
            (base + 's3_r2_b.wav'),
            (base + 's3_r3_b.wav'),
            (base + 's3_r4_b.wav'),
            (base + 's1_r1_bd.wav'),
            (base + 's1_r2_bd.wav'),
            (base + 's1_r3_bd.wav'),
            (base + 's1_r4_bd.wav'),
            (base + 's2_r1_bd.wav'),
            (base + 's2_r2_bd.wav'),
            (base + 's2_r3_bd.wav'),
            (base + 's2_r4_bd.wav'),
            (base + 's3_r1_bd.wav'),
            (base + 's3_r2_bd.wav'),
            (base + 's3_r3_bd.wav'),
            (base + 's3_r4_bd.wav'),
            (base + 's1_r1_c.wav'),
            (base + 's1_r2_c.wav'),
            (base + 's1_r3_c.wav'),
            (base + 's1_r4_c.wav'),
            (base + 's2_r1_c.wav'),
            (base + 's2_r2_c.wav'),
            (base + 's2_r3_c.wav'),
            (base + 's2_r4_c.wav'),
            (base + 's3_r1_c.wav'),
            (base + 's3_r2_c.wav'),
            (base + 's3_r3_c.wav'),
            (base + 's3_r4_c.wav'),
            (base + 's1_r1_o.wav'),
            (base + 's1_r2_o.wav'),
            (base + 's1_r3_o.wav'),
            (base + 's1_r4_o.wav'),
            (base + 's2_r1_o.wav'),
            (base + 's2_r2_o.wav'),
            (base + 's2_r3_o.wav'),
            (base + 's2_r4_o.wav'),
            (base + 's3_r1_o.wav'),
            (base + 's3_r2_o.wav'),
            (base + 's3_r3_o.wav'),
            (base + 's3_r4_o.wav'),
            (base + 's1_p1_o.wav'),
            (base + 's1_p2_o.wav'),
            (base + 's1_p3_o.wav'),
            (base + 's2_p1_o.wav'),
            (base + 's2_p2_o.wav'),
            (base + 's2_p3_o.wav'),
            (base + 's3_p1_o.wav'),
            (base + 's3_p2_o.wav'),
            (base + 's3_p3_o.wav')
        ];

        // for the instances of AudioBuffer
        var rirs = new Array(urls.length);

        // Get ArrayBuffer of impulse response by Ajax
        var load = function(url, index) {
            var xhr = new XMLHttpRequest();
            xhr.responseType = 'arraybuffer';

            // Timeout (1 minutes)
            xhr.timeout = 60000;

            xhr.ontimeout = function() {
                window.alert('Timeout.');
            };

            xhr.onerror = function() {
                window.alert('Ajax Error.');
            };

            xhr.onload = function() {
                if (xhr.status === 200) {
                    var arrayBuffer = xhr.response;  // Get ArrayBuffer

                    if (arrayBuffer instanceof ArrayBuffer) {
                        // The 2nd argument for decodeAudioData
                        var successCallback = function(audioBuffer) {
                            // Get the instance of AudioBuffer
                            rirs[index] = audioBuffer;

                            // The loading instances of AudioBuffer has completed ?
                            for (var i = 0, len = rirs.length; i < len; i++) {
                                if (rirs[i] === undefined) {
                                    return;
                                }
                            }

                            window.alert('The loading impulse responses has completed !!');

                            onloadCallback(rirs);
                        };

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

            xhr.open('GET', url, true);
            xhr.send(null);
        };

        urls.forEach(function(url, index) {
            load(url, index);
        });
    };

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