This repository has been archived by the owner on Nov 3, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Created c-api and stackmat.js to wrap it using webworkers. stackmat.h…
…tml is a basic demo.
- Loading branch information
Showing
8 changed files
with
1,782 additions
and
1,192 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
Large diffs are not rendered by default.
Oops, something went wrong.
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,117 @@ | ||
var Stackmat = Stackmat || {}; | ||
|
||
// webkit shim | ||
window.AudioContext = window.AudioContext || window.webkitAudioContext; | ||
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; | ||
|
||
(function() { | ||
"use strict"; | ||
|
||
var fskubeWorkerUrl; | ||
var worker; | ||
|
||
var audioContext; | ||
// Leak these nodes so the browser won't clean them up. Gross. | ||
var scriptProcessor; | ||
var microphoneInput; | ||
|
||
function createMicrophoneScriptProcessor() { | ||
navigator.getUserMedia( | ||
{ audio: true }, | ||
function(stream) { | ||
microphoneInput = audioContext.createMediaStreamSource(stream); | ||
microphoneInput.connect(scriptProcessor); | ||
microphoneScriptProcessorCreated(); | ||
}, | ||
function(e) { | ||
alert('No live audio input: ' + e); | ||
} | ||
); | ||
|
||
audioContext = new AudioContext(); | ||
// do the shimmy | ||
audioContext.createScriptProcessor = ( audioContext.createScriptProcessor || | ||
audioContext.createJavaScriptNode ); | ||
|
||
// A bigger buffer means more latency, but also gives us a better chance of not dropping | ||
// samples. | ||
var bufferSize = 8*1024; | ||
scriptProcessor = audioContext.createScriptProcessor(bufferSize, 1, 1); | ||
|
||
// This is silly. Apparently ScriptProcessorNode's need to be connected | ||
// to an output in order to fire. | ||
// http://stackoverflow.com/questions/19482155/do-webaudio-scriptprocessornodes-require-an-output-to-be-connected | ||
var zeroGainNode = audioContext.createGain(); | ||
zeroGainNode.gain = 0; | ||
scriptProcessor.connect(zeroGainNode); | ||
zeroGainNode.connect(audioContext.destination); | ||
} | ||
|
||
function microphoneScriptProcessorCreated() { | ||
worker = new Worker(fskubeWorkerUrl); | ||
|
||
var methods = { | ||
getLogLevels: function(logLevels) { | ||
if(getLogLevelsCallback) { | ||
getLogLevelsCallback(logLevels); | ||
getLogLevelsCallback = null; | ||
} | ||
}, | ||
newState: function(state) { | ||
if(Stackmat.onstackmatstate) { | ||
Stackmat.onstackmatstate(state); | ||
} | ||
} | ||
}; | ||
worker.addEventListener("message", function(e) { | ||
methods[e.data.method].apply(null, e.data.args); | ||
}); | ||
worker.addEventListener("error", function(e) { | ||
console.error("Worker error: " + e.message + "\n"); | ||
throw error; | ||
}); | ||
|
||
worker.postMessage({ | ||
method: "initialize", | ||
args: [ audioContext.sampleRate ] | ||
}); | ||
|
||
scriptProcessor.onaudioprocess = function(e) { | ||
worker.postMessage({ | ||
method: "addSample", | ||
args: [ e.inputBuffer.getChannelData(0) ] | ||
}); | ||
}; | ||
} | ||
|
||
Stackmat.initialize = function(fskubeWorkerUrl_) { | ||
fskubeWorkerUrl = fskubeWorkerUrl_; | ||
createMicrophoneScriptProcessor(); | ||
}; | ||
|
||
Stackmat.onstackmatstate = null; | ||
|
||
Stackmat.setLogLevels = function(levels) { | ||
if(!worker) { | ||
console.error("Must call Stackmat.initialize() first"); | ||
return; | ||
} | ||
worker.postMessage({ | ||
method: "setLogLevels", | ||
args: [ levels ] | ||
}); | ||
}; | ||
|
||
var getLogLevelsCallback; | ||
Stackmat.getLogLevels = function(cb) { | ||
if(!worker) { | ||
console.error("Must call Stackmat.initialize() first"); | ||
return; | ||
} | ||
getLogLevelsCallback = cb || function(levels) { console.log(levels); }; | ||
worker.postMessage({ | ||
method: "getLogLevels" | ||
}); | ||
}; | ||
|
||
})(); |
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
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 |
---|---|---|
@@ -1,14 +1,18 @@ | ||
#ifndef CAPI_H | ||
#define CAPI_H | ||
|
||
extern "C" { | ||
|
||
#include "stackmat.h" | ||
|
||
void *fskube_initialize(); | ||
// Note that this api only supports interpreting one stackmat at a time. | ||
// This seems fine to me. | ||
void fskube_initialize(unsigned int sampleRate); | ||
|
||
void fskube_destroy(void *fskube); | ||
bool fskube_addSample(double sample); | ||
|
||
bool fskube_addSample(void *fskube); | ||
fskube::StackmatState fskube_getState(); | ||
|
||
fskube::StackmatState fskube_getState(void * fskube); | ||
} | ||
|
||
#endif // CAPI_H |
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
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 |
---|---|---|
@@ -1,2 +1,37 @@ | ||
// These are here instead of in embind.cpp because embind can't deal with char*, | ||
// it can only handle std::string. We don't want to use std::string because it | ||
// seriously bloats the size of the generated code. | ||
Module.getLogLevels = Module.cwrap("getLogLevels", 'string'); | ||
Module.setLogLevels = Module.cwrap("setLogLevels", null, ['string']); | ||
|
||
var methods = { | ||
initialize: function(sampleRate) { | ||
Module.fskube_initialize(sampleRate); | ||
}, | ||
addSample: function(samples) { | ||
for(var i = 0; i < samples.length; i++) { | ||
var stateAvailable = Module.fskube_addSample(samples[i]); | ||
if(stateAvailable) { | ||
var state = Module.fskube_getState(); | ||
postMessage({ | ||
method: "newState", | ||
args: [ state ] | ||
}); | ||
} | ||
} | ||
}, | ||
setLogLevels: function(levels) { | ||
Module.setLogLevels(levels); | ||
}, | ||
getLogLevels: function() { | ||
postMessage({ | ||
method: "getLogLevels", | ||
args: [ Module.getLogLevels() ] | ||
}); | ||
} | ||
}; | ||
|
||
// TODO - for now we're assuming we're running in a webworker | ||
this.onmessage = function(e) { | ||
methods[e.data.method].apply(null, e.data.args); | ||
}; |
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,23 @@ | ||
<html> | ||
<head> | ||
<script src="release/stackmat.js"></script> | ||
<script> | ||
(function() { | ||
"use strict"; | ||
|
||
window.addEventListener("load", function() { | ||
var timeArea = document.getElementById("timeArea"); | ||
|
||
Stackmat.initialize("release/fskube.js"); | ||
Stackmat.onstackmatstate = function(state) { | ||
timeArea.innerHTML = state.millis; | ||
}; | ||
}); | ||
|
||
})(); | ||
</script> | ||
</head> | ||
<body> | ||
<div id="timeArea"></div> | ||
</body> | ||
</html> |