チャンネルリバース | ScriptProcessorNode

START / PAUSE
CHANNEL REVERSE
(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 createObjectURL
        window.URL = window.URL || window.webkitURL;

        // for legacy browsers
        context.createScriptProcessor = context.createScriptProcessor || context.createJavaScriptNode;

        // for selecting optimized buffer size
        var getBufferSize = function() {
            if (/(Win(dows )?NT 6\.2)/.test(navigator.userAgent)) {
                return 1024;  // Windows 8
            } else if (/(Win(dows )?NT 6\.1)/.test(navigator.userAgent)) {
                return 1024;  // Windows 7
            } else if (/(Win(dows )?NT 6\.0)/.test(navigator.userAgent)) {
                return 2048;  // Windows Vista
            } else if (/Win(dows )?(NT 5\.1|XP)/.test(navigator.userAgent)) {
                return 4096;  // Windows XP
            } else if (/Mac|PPC/.test(navigator.userAgent)) {
                return 1024;  // Mac OS X
            } else if (/Linux/.test(navigator.userAgent)) {
                return 8192;  // Linux
            } else if (/iPhone|iPad|iPod/.test(navigator.userAgent)) {
                return 2048;  // iOS
            } else {
                return 16384;  // Otherwise
            }
        };

        // Create the instance of ScriptProcessorNode
        var processor = context.createScriptProcessor(getBufferSize(), 2, 2);

        // for the instance of MediaElementAudioSourceNode
        var source = null;

        // for HTMLAudioElement
        var audio = null;

        // Start / Pause Button
        var controlButton = document.querySelector('button');

        // Toggle Channel Reverse
        var checkboxChannelReverse = document.querySelector('[type="checkbox"]');

        var volume = document.getElementById('range-volume').valueAsNumber;

        var setupAudio = function(src) {
            // Clear previous audio
            if (audio instanceof HTMLAudioElement) {
                processor.disconnect();
                processor.onaudioprocess = null;

                audio.pause();
                audio = null;

                controlButton.innerHTML = '<span class="icon-start"></span>';
            }

            // Create the instance of HTMLAudioElement
            audio = new Audio(src);
            audio.setAttribute('controls', false);

            // Create the instance of MediaElementAudioSourceNode after "onloadstart" event
            audio.addEventListener('loadstart', function(event) {
                window.alert('Start "' + event.type + '" !!');

                // Create the instance of MediaElementAudioSourceNode
                source = context.createMediaElementSource(audio);
            }, false);

            audio.addEventListener('play', function() {
                controlButton.innerHTML = '<span class="icon-pause"></span>';
            }, false);

            audio.addEventListener('pause', function() {
                controlButton.innerHTML = '<span class="icon-start"></span>';
            }, false);
        };

        /*
         * Event Listener
         */

        document.querySelector('[type="file"]').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 {
                setupAudio(window.URL.createObjectURL(file));
            }
        }, false);

        // Start or Pause audio
        controlButton.addEventListener(EventWrapper.CLICK, function() {
            if (!((source instanceof MediaElementAudioSourceNode) && (audio instanceof HTMLAudioElement))) {
                return;
            }

            if (audio.paused) {
                // Start onaudioprocess event

                // MediaElementAudioSourceNode (Input) -> ScriptProcessorNode (Channel Reverse, Volume) -> AudioDestinationNode (Output)
                source.connect(processor);
                processor.connect(context.destination);

                // Important !!
                audio.play();

                processor.onaudioprocess = function(event) {
                    // Get the instance of Float32Array for input data (Array size equals buffer size)
                    var inputLs = event.inputBuffer.getChannelData(0);  // Left  channel
                    var inputRs = event.inputBuffer.getChannelData(1);  // Right channel

                    // Get the instance of Float32Array for output data (Array size equals buffer size)
                    var outputLs = event.outputBuffer.getChannelData(0);  // Left  channel
                    var outputRs = event.outputBuffer.getChannelData(1);  // Right channel

                    for (var i = 0; i < this.bufferSize; i++) {
                        if (checkboxChannelReverse.checked) {
                            // Reverse
                            outputLs[i] = volume * inputRs[i];
                            outputRs[i] = volume * inputLs[i];
                        } else {
                            // Normal
                            outputLs[i] = volume * inputLs[i];
                            outputRs[i] = volume * inputRs[i];
                        }
                    }
                };
            } else {
                // Stop onaudioprocess event
                processor.disconnect();
                processor.onaudioprocess = null;

                audio.pause();
            }
        }, false);

        // Control Volume (without GainNode)
        document.getElementById('range-volume').addEventListener('input', function() {
            var min = 0;
            var max = 1;

            if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) {
                volume = this.valueAsNumber;
                document.getElementById('output-volume').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;
})();