-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 68278f7
Showing
9 changed files
with
633 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# Hark | ||
|
||
### Warning: This is a work in progress | ||
|
||
Hark is a tiny browser/commonJS module that listens to an audio stream, and emits events indicating whether the user is speaking or not. | ||
|
||
## Usage: | ||
|
||
`npm install hark` | ||
|
||
If you aren't using browserify, you'll want hark.bundle.js. | ||
|
||
```javascript | ||
var hark = require('../hark.js') | ||
|
||
var getUserMedia = require('getusermedia') | ||
|
||
getUserMedia(function(err, stream) { | ||
if (err) throw err | ||
|
||
var speechEvents = hark(stream); | ||
|
||
speechEvents.on('speaking', function() { | ||
console.log('speaking'); | ||
}); | ||
|
||
speechEvents.on('stopped_speaking', function() { | ||
console.log('stopped_speaking'); | ||
}); | ||
}); | ||
``` | ||
|
||
## Demo: | ||
|
||
Clone and open example/index.html | ||
|
||
## Requirements: | ||
|
||
Chrome with webrtc audio input flag enabled | ||
|
||
## License | ||
|
||
MIT | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
var browserify = require('browserify'), | ||
fs = require('fs'); | ||
|
||
var bundle = browserify(); | ||
bundle.add('./hark'); | ||
bundle.bundle({standalone: 'hark'}) | ||
.pipe(fs.createWriteStream('hark.bundle.js')); | ||
|
||
|
||
var demo = browserify(['./example/demo.js']) | ||
.bundle() | ||
.pipe(fs.createWriteStream('./example/demo.bundle.js')); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,303 @@ | ||
;(function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s<n.length;s++)i(n[s]);return i})({1:[function(require,module,exports){ | ||
var hark = require('../hark.js') | ||
var log = require('bows')('Demo'); | ||
|
||
var getUserMedia = require('getusermedia') | ||
|
||
getUserMedia(function(err, stream) { | ||
if (err) throw err | ||
|
||
var speechEvents = hark(stream); | ||
|
||
speechEvents.on('speaking', function() { | ||
document.write('Speaking<br>'); | ||
log('speaking'); | ||
}); | ||
|
||
speechEvents.on('stopped_speaking', function() { | ||
document.write('Not Speaking<br>'); | ||
log('stopped_speaking'); | ||
}); | ||
}); | ||
|
||
},{"../hark.js":2,"bows":3,"getusermedia":4}],4:[function(require,module,exports){ | ||
// getUserMedia helper by @HenrikJoreteg | ||
var func = (navigator.getUserMedia || | ||
navigator.webkitGetUserMedia || | ||
navigator.mozGetUserMedia || | ||
navigator.msGetUserMedia); | ||
|
||
|
||
module.exports = function (contstraints, cb) { | ||
var options; | ||
var haveOpts = arguments.length === 2; | ||
var defaultOpts = {video: true, audio: true}; | ||
|
||
// make contstraints optional | ||
if (!haveOpts) { | ||
cb = contstraints; | ||
contstraints = defaultOpts; | ||
} | ||
|
||
// treat lack of browser support like an error | ||
if (!func) return cb(new Error('notSupported')); | ||
|
||
func.call(navigator, contstraints, function (stream) { | ||
cb(null, stream); | ||
}, function (err) { | ||
cb(err); | ||
}); | ||
}; | ||
|
||
},{}],2:[function(require,module,exports){ | ||
var WildEmitter = require('wildemitter'); | ||
|
||
module.exports = function(stream) { | ||
var speakingThreshold = -45; | ||
var smoothing = 0.5; | ||
var pollPeriod = 100; | ||
var audioContext = new webkitAudioContext(); | ||
var sourceNode = audioContext.createMediaStreamSource(stream); | ||
var analyser = audioContext.createAnalyser(); | ||
var fftBins = new Float32Array(analyser.fftSize); | ||
|
||
analyser.fftSize = 512; | ||
analyser.smoothingTimeConstant = smoothing; | ||
sourceNode.connect(analyser); | ||
|
||
var emitter = new WildEmitter(); | ||
var speaking = false; | ||
|
||
// Poll the analyser node to determine if speaking | ||
// and emit events if changed | ||
setInterval(function() { | ||
var currentVolume = -Infinity; | ||
analyser.getFloatFrequencyData(fftBins) | ||
|
||
for(var i=0, ii=fftBins.length; i < ii; i++) { | ||
if (fftBins[i] > currentVolume && fftBins[i] < 0) { | ||
currentVolume = fftBins[i]; | ||
} | ||
}; | ||
|
||
if (currentVolume > speakingThreshold) { | ||
if (!speaking) { | ||
speaking = true; | ||
emitter.emit('speaking'); | ||
} | ||
} else { | ||
if (speaking) { | ||
speaking = false; | ||
emitter.emit('stopped_speaking'); | ||
} | ||
} | ||
}, pollPeriod); | ||
|
||
return emitter; | ||
} | ||
|
||
},{"wildemitter":5}],5:[function(require,module,exports){ | ||
/* | ||
WildEmitter.js is a slim little event emitter by @henrikjoreteg largely based | ||
on @visionmedia's Emitter from UI Kit. | ||
Why? I wanted it standalone. | ||
I also wanted support for wildcard emitters like this: | ||
emitter.on('*', function (eventName, other, event, payloads) { | ||
}); | ||
emitter.on('somenamespace*', function (eventName, payloads) { | ||
}); | ||
Please note that callbacks triggered by wildcard registered events also get | ||
the event name as the first argument. | ||
*/ | ||
module.exports = WildEmitter; | ||
|
||
function WildEmitter() { | ||
this.callbacks = {}; | ||
} | ||
|
||
// Listen on the given `event` with `fn`. Store a group name if present. | ||
WildEmitter.prototype.on = function (event, groupName, fn) { | ||
var hasGroup = (arguments.length === 3), | ||
group = hasGroup ? arguments[1] : undefined, | ||
func = hasGroup ? arguments[2] : arguments[1]; | ||
func._groupName = group; | ||
(this.callbacks[event] = this.callbacks[event] || []).push(func); | ||
return this; | ||
}; | ||
|
||
// Adds an `event` listener that will be invoked a single | ||
// time then automatically removed. | ||
WildEmitter.prototype.once = function (event, groupName, fn) { | ||
var self = this, | ||
hasGroup = (arguments.length === 3), | ||
group = hasGroup ? arguments[1] : undefined, | ||
func = hasGroup ? arguments[2] : arguments[1]; | ||
function on() { | ||
self.off(event, on); | ||
func.apply(this, arguments); | ||
} | ||
this.on(event, group, on); | ||
return this; | ||
}; | ||
|
||
// Unbinds an entire group | ||
WildEmitter.prototype.releaseGroup = function (groupName) { | ||
var item, i, len, handlers; | ||
for (item in this.callbacks) { | ||
handlers = this.callbacks[item]; | ||
for (i = 0, len = handlers.length; i < len; i++) { | ||
if (handlers[i]._groupName === groupName) { | ||
//console.log('removing'); | ||
// remove it and shorten the array we're looping through | ||
handlers.splice(i, 1); | ||
i--; | ||
len--; | ||
} | ||
} | ||
} | ||
return this; | ||
}; | ||
|
||
// Remove the given callback for `event` or all | ||
// registered callbacks. | ||
WildEmitter.prototype.off = function (event, fn) { | ||
var callbacks = this.callbacks[event], | ||
i; | ||
|
||
if (!callbacks) return this; | ||
|
||
// remove all handlers | ||
if (arguments.length === 1) { | ||
delete this.callbacks[event]; | ||
return this; | ||
} | ||
|
||
// remove specific handler | ||
i = callbacks.indexOf(fn); | ||
callbacks.splice(i, 1); | ||
return this; | ||
}; | ||
|
||
// Emit `event` with the given args. | ||
// also calls any `*` handlers | ||
WildEmitter.prototype.emit = function (event) { | ||
var args = [].slice.call(arguments, 1), | ||
callbacks = this.callbacks[event], | ||
specialCallbacks = this.getWildcardCallbacks(event), | ||
i, | ||
len, | ||
item; | ||
|
||
if (callbacks) { | ||
for (i = 0, len = callbacks.length; i < len; ++i) { | ||
if (callbacks[i]) { | ||
callbacks[i].apply(this, args); | ||
} else { | ||
break; | ||
} | ||
} | ||
} | ||
|
||
if (specialCallbacks) { | ||
for (i = 0, len = specialCallbacks.length; i < len; ++i) { | ||
if (specialCallbacks[i]) { | ||
specialCallbacks[i].apply(this, [event].concat(args)); | ||
} else { | ||
break; | ||
} | ||
} | ||
} | ||
|
||
return this; | ||
}; | ||
|
||
// Helper for for finding special wildcard event handlers that match the event | ||
WildEmitter.prototype.getWildcardCallbacks = function (eventName) { | ||
var item, | ||
split, | ||
result = []; | ||
|
||
for (item in this.callbacks) { | ||
split = item.split('*'); | ||
if (item === '*' || (split.length === 2 && eventName.slice(0, split[1].length) === split[1])) { | ||
result = result.concat(this.callbacks[item]); | ||
} | ||
} | ||
return result; | ||
}; | ||
|
||
},{}],3:[function(require,module,exports){ | ||
(function(window) { | ||
var logger = require('andlog'), | ||
goldenRatio = 0.618033988749895, | ||
hue = 0, | ||
padLength = 15, | ||
yieldColor, | ||
bows; | ||
|
||
yieldColor = function() { | ||
hue += goldenRatio; | ||
hue = hue % 1; | ||
return hue * 360; | ||
}; | ||
|
||
bows = function(str) { | ||
var msg; | ||
msg = "%c" + (str.slice(0, padLength)); | ||
msg += Array(padLength + 3 - msg.length).join(' ') + '|'; | ||
|
||
return logger.log.bind(logger, msg, "color: hsl(" + (yieldColor()) + ",99%,40%); font-weight: bold"); | ||
}; | ||
|
||
bows.config = function(config) { | ||
if (config.padLength) { | ||
return padLength = config.padLength; | ||
} | ||
}; | ||
|
||
if (typeof module !== 'undefined') { | ||
module.exports = bows; | ||
} else { | ||
window.bows = bows; | ||
} | ||
}).call(this); | ||
|
||
},{"andlog":6}],6:[function(require,module,exports){ | ||
// follow @HenrikJoreteg and @andyet if you like this ;) | ||
(function () { | ||
var inNode = typeof window === 'undefined', | ||
ls = !inNode && window.localStorage, | ||
out = {}; | ||
|
||
if (inNode) { | ||
module.exports = console; | ||
return; | ||
} | ||
|
||
if (ls && ls.debug && window.console) { | ||
out = window.console; | ||
} else { | ||
var methods = "assert,count,debug,dir,dirxml,error,exception,group,groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,time,timeEnd,trace,warn".split(","), | ||
l = methods.length, | ||
fn = function () {}; | ||
|
||
while (l--) { | ||
out[methods[l]] = fn; | ||
} | ||
} | ||
if (typeof exports !== 'undefined') { | ||
module.exports = out; | ||
} else { | ||
window.console = out; | ||
} | ||
})(); | ||
|
||
},{}]},{},[1]) | ||
; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
var hark = require('../hark.js') | ||
var log = require('bows')('Demo'); | ||
|
||
var getUserMedia = require('getusermedia') | ||
|
||
getUserMedia(function(err, stream) { | ||
if (err) throw err | ||
|
||
var speechEvents = hark(stream); | ||
|
||
speechEvents.on('speaking', function() { | ||
document.write('Speaking<br>'); | ||
log('speaking'); | ||
}); | ||
|
||
speechEvents.on('stopped_speaking', function() { | ||
document.write('Not Speaking<br>'); | ||
log('stopped_speaking'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<script src='demo.bundle.js'></script> |
Oops, something went wrong.