UNPKG

watson-speech

Version:

IBM Watson Speech to Text and Text to Speech SDK for web browsers.

219 lines (175 loc) 7.06 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>JSDoc: Source: webaudio-wav-stream.js</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: webaudio-wav-stream.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>'use strict'; var Transform = require('stream').Transform; var util = require('util'); function WebAudioWavStream(opts) { Transform.call(this, opts); this.sourceSampleRate = 4800; this.sampleRate = 16000; this.bufferUnusedSamples = new Float32Array(0); var self = this; this.on('pipe', function (src) { src.on('format', function (format) { self.sourceSampleRate = format.sampleRate; }); }); self.writeHeader(); } util.inherits(WebAudioWavStream, Transform); /** * Converts WebAudio to 'audio/l16' (raw wav) and downsamples to 16 kHz. * * Explanation for the math: The raw values captured from the Web Audio API are * in 32-bit Floating Point, between -1 and 1 (per the specification). * The values for 16-bit PCM range between -32768 and +32767 (16-bit signed integer). * Multiply to control the volume of the output. We store in little endian. * * @param {Object} buffer Microphone/MediaElement audio chunk * @return {Buffer} 'audio/l16' chunk * @deprecated This method is deprecated */ WebAudioWavStream.prototype._exportDataBufferTo16Khz = function (nodebuffer) { var bufferNewSamples = new Float32Array(nodebuffer.buffer), buffer = null, newSamples = bufferNewSamples.length, unusedSamples = this.bufferUnusedSamples.length; if (unusedSamples > 0) { buffer = new Float32Array(unusedSamples + newSamples); for (var i = 0; i &lt; unusedSamples; ++i) { buffer[i] = this.bufferUnusedSamples[i]; } for (i = 0; i &lt; newSamples; ++i) { buffer[unusedSamples + i] = bufferNewSamples[i]; } } else { buffer = bufferNewSamples; } // downsampling variables var filter = [ -0.037935, -0.00089024, 0.040173, 0.019989, 0.0047792, -0.058675, -0.056487, -0.0040653, 0.14527, 0.26927, 0.33913, 0.26927, 0.14527, -0.0040653, -0.056487, -0.058675, 0.0047792, 0.019989, 0.040173, -0.00089024, -0.037935 ], samplingRateRatio = this.sourceSampleRate / 16000, nOutputSamples = Math.floor((buffer.length - filter.length) / (samplingRateRatio)) + 1, pcmEncodedBuffer16k = new ArrayBuffer(nOutputSamples * 2), dataView16k = new DataView(pcmEncodedBuffer16k), index = 0, volume = 0x7FFF, //range from 0 to 0x7FFF to control the volume nOut = 0; for (i = 0; i + filter.length - 1 &lt; buffer.length; i = Math.round(samplingRateRatio * nOut)) { var sample = 0; for (var j = 0; j &lt; filter.length; ++j) { sample += buffer[i + j] * filter[j]; } sample *= volume; try { dataView16k.setInt16(index, sample, true); // 'true' -> means little endian } catch (ex) { // chrome occasionally throws RangeError: Offset is outside the bounds of the DataView // todo: actually fix it instead of just ignoring the error.. } index += 2; nOut++; } var indexSampleAfterLastUsed = Math.round(samplingRateRatio * nOut); var remaining = buffer.length - indexSampleAfterLastUsed; if (remaining > 0) { this.bufferUnusedSamples = new Float32Array(remaining); for (i = 0; i &lt; remaining; ++i) { this.bufferUnusedSamples[i] = buffer[indexSampleAfterLastUsed + i]; } } else { this.bufferUnusedSamples = new Float32Array(0); } return new Buffer(dataView16k.buffer); }; /** * The max size of the "data" chunk of a WAVE file. This is the max unsigned * 32-bit int value, minus 100 bytes (overkill, 44 would be safe) for the header. * * From https://github.com/TooTallNate/node-wav/blob/master/lib/writer.js * * @api private */ var MAX_WAV = 4294967295 - 100; function writeString(view, offset, string) { for (var i = 0; i &lt; string.length; i++){ view.setUint8(offset + i, string.charCodeAt(i)); } } WebAudioWavStream.prototype.writeHeader = function writeHeader() { var buffer = new ArrayBuffer(44); var view = new DataView(buffer); var length = MAX_WAV; // can't use the actuall length because we don't know it yet var numChannels = 1; var sampleRate = 16000; /* RIFF identifier */ writeString(view, 0, 'RIFF'); /* RIFF chunk length */ view.setUint32(4, 36 + length, true); /* RIFF type */ writeString(view, 8, 'WAVE'); /* format chunk identifier */ writeString(view, 12, 'fmt '); /* format chunk length */ view.setUint32(16, 16, true); /* sample format (raw PCM) */ view.setUint16(20, 1, true); /* channel count */ view.setUint16(22, numChannels, true); /* sample rate */ view.setUint32(24, sampleRate, true); /* byte rate (sample rate * block align) */ view.setUint32(28, sampleRate * 4, true); /* block align (channel count * bytes per sample) */ view.setUint16(32, numChannels * 2, true); /* bits per sample */ view.setUint16(34, 16, true); /* data chunk identifier */ writeString(view, 36, 'data'); /* data chunk length */ view.setUint32(40, length, true); this.push(new Buffer(buffer)); }; WebAudioWavStream.prototype._transform = function (chunk, encoding, next) { this.push(this._exportDataBufferTo16Khz(chunk)); next(); }; WebAudioWavStream.prototype._flush = function (next) { // todo: handle anything left in this.bufferUnusedSamples here... next(); }; module.exports = WebAudioWavStream; </code></pre> </article> </section> </div> <nav> <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="FormatStream.html">FormatStream</a></li><li><a href="MediaElementAudioStream.html">MediaElementAudioStream</a></li><li><a href="RecognizeStream.html">RecognizeStream</a></li><li><a href="TimingStream.html">TimingStream</a></li></ul><h3>Events</h3><ul><li><a href="MicrophoneStream.html#event:data">data</a></li><li><a href="MicrophoneStream.html#event:raw">raw</a></li><li><a href="RecognizeStream.html#event:connection-close">connection-close</a></li><li><a href="RecognizeStream.html#event:data">data</a></li><li><a href="RecognizeStream.html#event:error">error</a></li><li><a href="RecognizeStream.html#event:results">results</a></li></ul><h3>Global</h3><ul><li><a href="global.html#MAX_WAV">MAX_WAV</a></li></ul> </nav> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.0</a> on Mon Feb 08 2016 16:11:17 GMT+0000 (UTC) </footer> <script> prettyPrint(); </script> <script src="scripts/linenumber.js"> </script> </body> </html>