{"version":3,"file":"msr_helper_stereoaudio.min.js","sources":["../src/msr_helper_stereoaudio.js"],"sourcesContent":["/* jshint ignore:start */\ndefine(['jquery',\n        'core/log'],\n    function ($, log) {\n\n        \"use strict\"; // jshint ;_;\n\n        log.debug('PoodLL Stereo Audio Recorder Helper: initialising');\n\n        return {\n\n            //globals??\n            scriptprocessornode: null,\n            requestDataInvoked: false,\n            recordingLength: 0,\n            isPaused: false,\n\n            // variables\n            deviceSampleRate: 48000,//44100, // range: 22050 to 96000\n            leftchannel: [],\n            rightchannel: [],\n            recording: false,\n            volume: null,\n            audioInput: null,\n            context: null,\n            sampleRate: 0,\n            mimeType: 0,\n            isPCM: false,\n            numChannels: 1,\n            msr: null,\n            audioctx: null,\n            mediaStream: null,\n            volumeGainNode: null,\n\n            //for making multiple instances\n            clone: function () {\n                return $.extend(true, {}, this);\n            },\n\n\n            init: function (msr, mediaStream, audioctx) {\n\n                this.msr = msr;\n                this.audioctx = audioctx;\n                this.mediaStream = mediaStream;\n                this.deviceSampleRate = audioctx.sampleRate;\n                //this.sampleRate = msr.sampleRate || this.deviceSampleRate;\n                this.sampleRate =  this.deviceSampleRate;\n                this.mimeType = msr.mimeType || 'audio/wav';\n                this.isPCM = this.mimeType.indexOf('audio/pcm') > -1;\n                this.numChannels = msr.audioChannels || 1;\n                log.debug('stereohelper mimetype: ' + this.mimeType);\n                //and then further init'ing\n                this.misc();\n\n            },\n\n            misc: function () {\n                var that = this;\n                // creates the audio context\n                var context = this.audioctx;\n\n                // creates a gain node\n                this.volumeGainNode = context.createGain();\n\n                var volume = this.volumeGainNode;\n\n                // creates an audio node from the microphone incoming stream\n                //the node chain is audioinput -> volume -> analyser -> scriptprocessingnode\n                this.audioInput = context.createMediaStreamSource(this.mediaStream);\n\n                // creates an audio node from the microphone incoming stream\n                var audioInput = this.audioInput;\n\n                // connect the stream to the gain node\n                audioInput.connect(volume);\n\n                /* From the spec: This value controls how frequently the audioprocess event is\n                 dispatched and how many sample-frames need to be processed each call.\n                 Lower values for buffer size will result in a lower (better) latency.\n                 Higher values will be necessary to avoid audio breakup and glitches\n                 Legal values are 256, 512, 1024, 2048, 4096, 8192, and 16384.*/\n                var bufferSize = this.msr.bufferSize || 2048;\n                if (this.msr.bufferSize === 0) {\n                    bufferSize = 0;\n                }\n\n                var scriptprocessornode = null;\n                if (context.createJavaScriptNode) {\n                    scriptprocessornode = context.createJavaScriptNode(bufferSize, this.numChannels, this.numChannels);\n                } else if (context.createScriptProcessor) {\n                    scriptprocessornode = context.createScriptProcessor(bufferSize, this.numChannels, this.numChannels);\n                } else {\n                    throw 'WebAudio API has no support on this browser.';\n                }\n\n                this.bufferSize = scriptprocessornode.bufferSize;\n                this.requestDataInvoked = false;\n\n                // sometimes \"scriptprocessornode\" disconnects from he destination-node\n                // and there is no exception thrown in this case.\n                // and obviously no further \"ondataavailable\" events will be emitted.\n                // below global-scope variable is added to debug such unexpected but \"rare\" cases.\n                this.scriptprocessornode = scriptprocessornode;\n\n                if (this.numChannels === 1) {\n                    log.debug('All right-channels are skipped.');\n                }\n\n                this.isPaused = false;\n\n                //http://webaudio.github.io/web-audio-api/#the-scriptprocessornode-interface\n                scriptprocessornode.onaudioprocess = function (e) {\n                    if (!that.recording || that.requestDataInvoked || that.isPaused) {\n                        return;\n                    }\n\n                    var left = e.inputBuffer.getChannelData(0);\n                    that.leftchannel.push(new Float32Array(left));\n\n                    if (that.numChannels === 2) {\n                        var right = e.inputBuffer.getChannelData(1);\n                        that.rightchannel.push(new Float32Array(right));\n                    }\n                    that.recordingLength += that.bufferSize;\n                };\n\n                volume.connect(this.msr.audioanalyser.core);\n                // volume.connect(this.scriptprocessornode);\n                this.msr.audioanalyser.core.connect(scriptprocessornode);\n                scriptprocessornode.connect(context.destination);\n\n            },\n\n            record: function () {\n                this.recording = true;\n                // reset the buffers for the new recording\n                this.leftchannel.length = this.rightchannel.length = 0;\n                this.recordingLength = 0;\n            },\n\n            encodeWAV: function(samples) {\n                var buffer = new ArrayBuffer(44 + samples.length * 2);\n                var view = new DataView(buffer);\n\n                /* RIFF identifier */\n                this.writeString(view, 0, 'RIFF');\n                /* RIFF chunk length */\n                view.setUint32(4, 36 + samples.length * 2, true);\n                /* RIFF type */\n                this.writeString(view, 8, 'WAVE');\n                /* format chunk identifier */\n                this.writeString(view, 12, 'fmt ');\n                /* format chunk length */\n                view.setUint32(16, 16, true);\n                /* sample format (raw) */\n                view.setUint16(20, 1, true);\n                /* channel count */\n                view.setUint16(22, this.numChannels, true);\n                /* sample rate */\n                view.setUint32(24, this.sampleRate, true);\n                /* byte rate (sample rate * block align) */\n                view.setUint32(28, this.sampleRate * 4, true);\n                /* block align (channel count * bytes per sample) */\n                view.setUint16(32, this.numChannels * 2, true);\n                /* bits per sample */\n                view.setUint16(34, 16, true);\n                /* data chunk identifier */\n                this.writeString(view, 36, 'data');\n                /* data chunk length */\n                view.setUint32(40, samples.length * 2, true);\n\n                this.floatTo16BitPCM(view, 44, samples);\n                log.debug(samples.length * 2);\n\n                return view;\n            },\n\n            floatTo16BitPCM: function(output, offset, input) {\n                for (var i = 0; i < input.length; i++, offset += 2) {\n                    var s = Math.max(-1, Math.min(1, input[i]));\n                    output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);\n                }\n            },\n\n            writeString: function(view, offset, string) {\n                for (var i = 0; i < string.length; i++) {\n                    view.setUint8(offset + i, string.charCodeAt(i));\n                }\n            },\n\n            requestData: function () {\n                if (this.isPaused) {\n                    return;\n                }\n\n                if (this.recordingLength === 0) {\n                    this.requestDataInvoked = false;\n                    return;\n                }\n\n                this.requestDataInvoked = true;\n                // clone stuff\n                var internalLeftChannel = this.leftchannel.slice(0);\n                var internalRightChannel = this.rightchannel.slice(0);\n                var internalRecordingLength = this.recordingLength;\n\n                // reset the buffers for the new recording\n                this.leftchannel.length = this.rightchannel.length = [];\n                this.recordingLength = 0;\n                this.requestDataInvoked = false;\n\n                var leftBuffer = this.mergeBuffers(internalLeftChannel, internalRecordingLength);\n                var interleaved = leftBuffer;\n\n                // we interleave both channels together\n                if (this.numChannels === 2) {\n                    var rightBuffer = this.mergeBuffers(internalRightChannel, internalRecordingLength); // bug fixed via #70,#71\n                    interleaved = this.interleave(leftBuffer, rightBuffer);\n                }\n                var dataview = this.encodeWAV(interleaved);\n                var audioBlob = new Blob([dataview], {type: 'audio/wav'});\n                this.msr.ondataavailable(audioBlob);\n            },\n\n            xrequestData: function () {\n\n                if (this.isPaused) {\n                    return;\n                }\n\n                if (this.recordingLength === 0) {\n                    this.requestDataInvoked = false;\n                    return;\n                }\n\n                this.requestDataInvoked = true;\n                // clone stuff\n                var internalLeftChannel = this.leftchannel.slice(0);\n                var internalRightChannel = this.rightchannel.slice(0);\n                var internalRecordingLength = this.recordingLength;\n\n                // reset the buffers for the new recording\n                this.leftchannel.length = this.rightchannel.length = [];\n                this.recordingLength = 0;\n                this.requestDataInvoked = false;\n\n                // we flat the left and right channels down\n                var leftBuffer = this.mergeBuffers(internalLeftChannel, internalRecordingLength);\n\n                var interleaved = leftBuffer;\n\n                // we interleave both channels together\n                if (this.numChannels === 2) {\n                    var rightBuffer = this.mergeBuffers(internalRightChannel, internalRecordingLength); // bug fixed via #70,#71\n                    this.interleaved = this.interleave(leftBuffer, rightBuffer);\n                }\n\n                if (this.isPCM) {\n                    // our final binary blob\n                    var blob = new Blob([this.convertoFloat32ToInt16(interleaved)], {\n                        type: 'audio/pcm'\n                    });\n\n                    this.msr.ondataavailable(blob);\n                    return;\n                }\n\n                // we create our wav file\n                var buffer = new ArrayBuffer(44 + interleaved.length * 2);\n                var view = new DataView(buffer);\n\n                // RIFF chunk descriptor\n                this.writeUTFBytes(view, 0, 'RIFF');\n\n                // -8 (via #97)\n                view.setUint32(4, 44 + interleaved.length * 2 - 8, true);\n\n                this.writeUTFBytes(view, 8, 'WAVE');\n                // FMT sub-chunk\n                this.writeUTFBytes(view, 12, 'fmt ');\n                view.setUint32(16, 16, true);\n                view.setUint16(20, 1, true);\n                // stereo (2 channels)\n                view.setUint16(22, this.numChannels, true);\n                view.setUint32(24, this.sampleRate, true);\n                view.setUint32(28, this.sampleRate * this.numChannels * 2, true); // numChannels * 2 (via #71)\n                view.setUint16(32, this.numChannels * 2, true);\n                view.setUint16(34, 16, true);\n                // data sub-chunk\n                this.writeUTFBytes(view, 36, 'data');\n                view.setUint32(40, interleaved.length * 2, true);\n\n                // write the PCM samples\n                var lng = interleaved.length;\n                var index = 44;\n                var volume = 1;\n                for (var i = 0; i < lng; i++) {\n                    view.setInt16(index, interleaved[i] * (0x7FFF * volume), true);\n                    index += 2;\n                }\n\n                // our final binary blob\n                var blob = new Blob([view], {\n                    type: 'audio/wav'\n                });\n                this.msr.ondataavailable(blob);\n            },\n\n            stop: function () {\n                // we stop recording\n                this.recording = false;\n                this.requestData();\n                this.audioInput.disconnect();\n            },\n\n            interleave: function (leftChannel, rightChannel) {\n                var length = leftChannel.length + rightChannel.length;\n                var result = new Float32Array(length);\n\n                var inputIndex = 0;\n\n                for (var index = 0; index < length;) {\n                    result[index++] = leftChannel[inputIndex];\n                    result[index++] = rightChannel[inputIndex];\n                    inputIndex++;\n                }\n                return result;\n            },\n\n            mergeBuffers: function (channelBuffer, recordingLength) {\n                var result = new Float32Array(recordingLength);\n                var offset = 0;\n                var lng = channelBuffer.length;\n                for (var i = 0; i < lng; i++) {\n                    var buffer = channelBuffer[i];\n                    result.set(buffer, offset);\n                    offset += buffer.length;\n                }\n                return result;\n            },\n\n            writeUTFBytes: function (view, offset, string) {\n                var lng = string.length;\n                for (var i = 0; i < lng; i++) {\n                    view.setUint8(offset + i, string.charCodeAt(i));\n                }\n            },\n\n            convertoFloat32ToInt16: function (buffer) {\n                var l = buffer.length;\n                var buf = new Int16Array(l)\n\n                while (l--) {\n                    buf[l] = buffer[l] * 0xFFFF; //convert to 16 bit\n                }\n                return buf.buffer\n            },\n\n\n            pause: function () {\n                this.isPaused = true;\n            },\n\n            resume: function () {\n                this.isPaused = false;\n            }\n\n        };// end of returned object\n    });// total end\n"],"names":["define","$","log","debug","scriptprocessornode","requestDataInvoked","recordingLength","isPaused","deviceSampleRate","leftchannel","rightchannel","recording","volume","audioInput","context","sampleRate","mimeType","isPCM","numChannels","msr","audioctx","mediaStream","volumeGainNode","clone","extend","this","init","indexOf","audioChannels","misc","that","createGain","createMediaStreamSource","connect","bufferSize","createJavaScriptNode","createScriptProcessor","onaudioprocess","e","left","inputBuffer","getChannelData","push","Float32Array","right","audioanalyser","core","destination","record","length","encodeWAV","samples","buffer","ArrayBuffer","view","DataView","writeString","setUint32","setUint16","floatTo16BitPCM","output","offset","input","i","s","Math","max","min","setInt16","string","setUint8","charCodeAt","requestData","internalLeftChannel","slice","internalRightChannel","internalRecordingLength","leftBuffer","mergeBuffers","interleaved","rightBuffer","interleave","dataview","audioBlob","Blob","type","ondataavailable","xrequestData","blob","convertoFloat32ToInt16","writeUTFBytes","lng","index","stop","disconnect","leftChannel","rightChannel","result","inputIndex","channelBuffer","set","l","buf","Int16Array","pause","resume"],"mappings":"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"}