MediaStreamAudioSourceNode

START STREAM
MediaStreamAudioSourceNode
MediaStreamAudioSourceNode
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;
        }

        navigator.getUserMedia = navigator.getUserMedia       ||
                                 navigator.webkitGetUserMedia ||
                                 navigator.mozGetUserMedia;

        if (navigator.getUserMedia === undefined) {
            window.alert('Cannot use WebRTC.');
            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';
        };

        // for drawing sound wave

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

        var timerids = [null, null];
        var interval = document.getElementById('range-draw-interval').valueAsNumber;

        var drawWave = function(canvas, canvasContext) {
            return function(domain) {
                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 middle = (innerHeight / 2) + paddingTop;

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

                // Draw sound wave
                canvasContext.beginPath();

                var data = null;

                switch (domain) {
                    case 'time' :
                        data = new Uint8Array(analyser.fftSize);
                        analyser.getByteTimeDomainData(data);

                        canvasContext.moveTo(paddingLeft, middle);

                        for (var i = 0, len = data.length; i < len; i++) {
                            var x = Math.floor((i / len) * innerWidth) + paddingLeft;
                            var y = Math.floor((1 - (data[i] / 255)) * innerHeight) + paddingTop;

                            canvasContext.lineTo(x, y);

                            // Sampling period
                            var period = 1 / context.sampleRate;

                            // This value is the number of samples during 5 msec
                            var n5msec = Math.floor(5 * Math.pow(10, -3) * context.sampleRate);

                            // 5 msec ?
                            if ((i % n5msec) === 0) {
                                var sec  = i * period;             // index -> time
                                var msec = sec * Math.pow(10, 3);  // sec -> msec
                                var text = Math.round(msec) + ' msec';

                                canvasContext.fillStyle = 'rgba(255, 0, 0, 1.0)';
                                canvasContext.fillRect(x, paddingTop, 1, innerHeight);

                                canvasContext.fillStyle = 'rgba(255, 255, 255, 1.0)';
                                canvasContext.font      = '13px "Times New Roman"';
                                canvasContext.fillText(text, (x - (canvasContext.measureText(text).width / 2)), (height - 3));
                            }
                        }

                        break;
                    case 'frequency' :
                        data = new Float32Array(analyser.frequencyBinCount / 4);
                        analyser.getFloatFrequencyData(data);

                        analyser.maxDecibels = 0;
                        analyser.minDecibels = -60;

                        var range = analyser.maxDecibels - analyser.minDecibels;

                        canvasContext.moveTo(paddingLeft, innerBottom);

                        for (var i = 0, len = data.length; i < len; i++) {
                            var x = Math.floor((i / len) * innerWidth) + paddingLeft;
                            var y = Math.floor(-1 * ((data[i] - analyser.maxDecibels) / range) * innerHeight) + paddingTop;

                            canvasContext.lineTo(x, y);

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

                            // This value is the number of samples during 440 Hz
                            var n440Hz = Math.floor(440 / fsDivN);

                            // 440 Hz ?
                            if (i % n440Hz === 0) {
                                var f    = Math.floor(440 * (i / n440Hz));  // index -> frequency
                                var text = (f < 1000) ? (f + ' Hz') : ((f / 1000) + ' kHz');

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

                        break;
                    default :
                        break;
                }

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

                switch (domain) {
                    case 'time' :
                        // Draw grid (Y)
                        canvasContext.fillStyle = 'rgba(255, 0, 0, 1.0)';
                        canvasContext.fillRect(paddingLeft, paddingTop,  innerWidth, 1);
                        canvasContext.fillRect(paddingLeft, middle,      innerWidth, 1);
                        canvasContext.fillRect(paddingLeft, innerBottom, innerWidth, 1);

                        // Draw text (Y)
                        canvasContext.fillStyle = 'rgba(255, 255, 255, 1.0)';
                        canvasContext.font      = '13px "Times New Roman"';
                        canvasContext.fillText(' 1.00', 3, paddingTop);
                        canvasContext.fillText(' 0.00', 3, middle);
                        canvasContext.fillText('-1.00', 3, innerBottom);

                        break;
                    case 'frequency' :
                        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      = '13px "Times New Roman"';
                            canvasContext.fillText((i + ' dB'), 3, gy);
                        }

                        break;
                    default :
                        break;
                }

                var self = arguments.callee;

                switch (domain) {
                    case 'time' :
                        timerids[0] = window.setTimeout(function() {
                            self(domain);
                        }, interval);

                        break;
                    case 'frequency' :
                        timerids[1] = window.setTimeout(function() {
                            self(domain);
                        }, interval);

                        break;
                    default :
                        break;
                }
            };
        };

        var canvases = {
            time     : null,
            spectrum : null
        };

        var contexts = {
            time     : null,
            spectrum : null
        };

        canvases.time     = document.querySelectorAll('canvas')[0];
        canvases.spectrum = document.querySelectorAll('canvas')[1];

        contexts.time     = canvases.time.getContext('2d');
        contexts.spectrum = canvases.spectrum.getContext('2d');

        var drawTimeDomain = drawWave(canvases.time,     contexts.time);
        var drawSpectrum   = drawWave(canvases.spectrum, contexts.spectrum);

        // Access microphone
        var medias = {audio : true, video : false};

        var successCallback = function(stream) {
            // Create the instance of MediaStreamAudioSourceNode
            var source = context.createMediaStreamSource(stream);

            // MediaStreamAudioSourceNode (Input) -> AnalyserNode (Visualization)
            source.connect(analyser);

            drawTimeDomain('time');
            drawSpectrum('frequency');

            displayProperties(source, 'mediastreamaudiosourcenode-properties', 'MediaStreamAudioSourceNode');
        };

        var errorCallback = function(error) {
            console.error(error);
        };

        // Start Stream
        document.getElementById('button-start-stream').addEventListener(EventWrapper.CLICK, function() {
            navigator.getUserMedia(medias, successCallback, errorCallback);
        }, false);

        // Control Draw Interval
        document.getElementById('range-draw-interval').addEventListener('input', function() {
            interval = this.valueAsNumber;
            document.getElementById('output-draw-interval').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;
})();