ScriptProcessorNode

START / STOP
Processed Buffer Size
ScriptProcessorNode
ScriptProcessorNode
PropertyValuehasOwnProperty
AudioProcessingEvent
AudioProcessingEvent
PropertyValuehasOwnProperty
AudioNode
AudioNode
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;

            if (document.getElementById(tableid).parentNode.previousElementSibling !== null) {
                document.getElementById(tableid).parentNode.previousElementSibling.style.display = 'block';
            }
        };

        // 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 OscillatorNode
        var oscillator = null;

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

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

        // for processed buffer size
        var count = 0;

        // Get DOM for displaying processed buffer size
        var outputBufferSize = document.querySelector('[type="number"]');

        /*
         * Event Listener
         */

        // Start or Stop sound
        document.querySelector('button').addEventListener(EventWrapper.CLICK, function() {
            if (isStop) {
                // Start onaudioprocess event

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

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

                // OscillatorNode (Input) -> ScriptProcessorNode (Volume) -> AudioDestinationNode (Output);
                oscillator.connect(processor);
                processor.connect(context.destination);

                // Important !!
                oscillator.start(0);

                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++) {
                        outputLs[i] = volume * inputLs[i];
                        outputRs[i] = volume * inputRs[i];
                    }

                    displayProperties(event, 'audioprocessingevent-properties', 'AudioProcessingEvent');

                    outputBufferSize.valueAsNumber = count * this.bufferSize;
                    count++;
                };

                isStop = false;
                this.innerHTML = '<span class="icon-pause"></span>';
            } else {
                // Stop onaudioprocess event
                processor.disconnect();
                processor.onaudioprocess = null;

                oscillator.stop(0);

                isStop = true;
                this.innerHTML = '<span class="icon-start"></span>';

                isCreateTable = false;

                window.alert('Execute "disconnect" and Clear "onaudioprocess" event handler !!');
            }
        }, 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);

        /*
         * Display properties
         */

        // Prototype chain
        var prototypes = {};

        // Prototype chain
        prototypes.ScriptProcessorNode = Object.getPrototypeOf(processor);                       // ScriptProcessorNode instance -> ScriptProcessorNode
        prototypes.AudioNode           = Object.getPrototypeOf(prototypes.ScriptProcessorNode);  // ScriptProcessorNode -> AudioNode

        displayProperties(processor,            'scriptprocessornode-properties', 'ScriptProcessorNode');
        // displayProperties(prototypes.AudioNode, 'audionode-properties',           'AudioNode');
    };

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