Commit 67535016 authored by Max-Ferdinand Suffel's avatar Max-Ferdinand Suffel
Browse files

Merge branch 'master' of uwgitlab:k/481

parents cf65b373 306536c6
How to run
```
$ nodemon server.js
$ python -m http.server # or python -m SimpleHTTPServer
```
Now go to `localhost:8000`.
\ No newline at end of file
// DEBUG switch.
var DEBUG = false;
// Import filesystem.
var fs = require('fs');
var app = require('http').createServer();
// Import socket.io.
var io = require('socket.io')(app);
// Import enums.
var Enum = require('enum');
// Create serial port object.
var SerialPort = require("serialport").SerialPort;
// ThinkGear Communication Protocol constants.
var AUTOCONNECT = 0xC2;
var CONNECT = 0xC0C00C;
var DISCONNECT = 0xC1;
var SYNC = 0xAA;
var EXCODE = 0x55;
var CODE_ATTENTION = 0x04
var CODE_MEDITATION = 0x05
// The object that holds the timer that reties connection
var connect_timer = null;
// Obtain name of user-speficied serial port device.
var serialPortName = process.argv[2];
if (!serialPortName) {
console.log("Serial port name missing! => node NodeTGC.js <path-to-serial-port-device>")
process.exit(1);
}
// Open serial port of the Neurosky MindWave using the given name.
var nmwSerialPort = new SerialPort(serialPortName, {
baudRate : 115200 // According the chip specification the baudrate has to be 115200.
});
var nmwSerialPortOpen = false;
// Start socket.io server listening on port 3000.
io.listen(3000);
// Handle user input.
var readline = require('readline'),
rl = readline.createInterface(process.stdin, process.stdout);
rl.on('close', function() {
if (nmwSerialPortOpen) {
// Disconnect from the Neurosky MindWave.
nmwSerialPort.write(new Buffer([DISCONNECT], 'hex'), function(error, results) {
if (error || results != 1) {
console.log("Could not disconnect from the Neurosky MindWave." + err);
process.exit(1);
} else {
console.log("Disconnect...");
}
});
nmwSerialPort.drain();
nmwSerialPort.close();
}
io.close();
process.exit(0);
});
// Listen for open-events: Called when the serial port connection is established.
nmwSerialPort.on("open", function (error) {
if (error) {
console.log("Serial port failed to open: " + error);
} else {
nmwSerialPortOpen = true;
console.log("Serial port to \"" + serialPortName + "\" successfully openend.");
// Attach a listener for the incoming packets from the serial port.
nmwSerialPort.on("data", receivePackets);
connect_timer = setInterval(connect, 10000);
}
});
function connect() {
// Autoconnect to the first discovered Neurosky MindWave.
nmwSerialPort.write(new Buffer([AUTOCONNECT], 'hex'), function(error, results) {
if (error || results != 1) {
console.log("Could not connect to the Neurosky MindWave." + err);
process.exit(1);
} else {
console.log("Connecting...");
}
});
}
// State Machine for the serial port data processing.
var ProcessState = new Enum(['SYNC', 'SYNC_CHECK', 'PAYLOAD_LENGTH', 'PAYLOAD', 'CHECKSUM']);
var state = ProcessState.SYNC; // Initial state is SYNC.
var payloadLength;
var payloadIndex;
var payloadBuffer;
var checksum;
// Process the incoming packets from the serial port.
// TODO: Decouple processing of the packets from the checksum check => new PROCESS state!
function receivePackets (data) {
for (var i = 0; i < data.length; i++) {
// Obtain the next byte from the serial port connection.
var next_byte = data.readUInt8(i);
if (DEBUG) console.log ("Process Next Byte: " + next_byte.toString(16));
switch (state) {
// Seek for synchronization byte.
case ProcessState.SYNC:
if (next_byte == SYNC) {
state = ProcessState.SYNC_CHECK;
if (DEBUG) console.log("SYNC");
}
break;
// Double check the synchronization byte.
case ProcessState.SYNC_CHECK:
if (next_byte == SYNC) {
state = ProcessState.PAYLOAD_LENGTH;
if (DEBUG) console.log("SYNC DOUBLECHECK");
} else {
state = ProcessState.SYNC;
if (DEBUG) console.log("SYNC DOUBLECHECK FAILED");
}
break;
// Obtain the payload length.
case ProcessState.PAYLOAD_LENGTH:
payloadLength = next_byte;
if (payloadLength > 170) {
state = ProcessState.SYNC;
if (DEBUG) console.log("PAYLOAD TOO LARGE (>170)");
} else if (payloadLength == 170) {
if (DEBUG) console.log("PAYLOAD == SYNC");
} else { // Pre-Condition: payLoadLength < 170
// Create a suitable payload buffer for the upcoming serial data.
payloadBuffer = new Buffer(payloadLength, 'hex');
payloadIndex = 0;
checksum = 0;
state = ProcessState.PAYLOAD;
if (DEBUG) console.log("PAYLOAD LENGTH IS: " + payloadLength);
}
break;
// Receive the payload and compute the checksum in parallel.
case ProcessState.PAYLOAD:
if (payloadIndex < payloadLength) {
payloadBuffer[payloadIndex] = next_byte;
checksum += next_byte;
++payloadIndex;
if (DEBUG) console.log("RECEIVE PAYLOAD [" + payloadIndex + "," + payloadBuffer.toString('hex') + "]");
}
if (payloadIndex == payloadLength) {
checksum = checksum & 0xFF;
checksum = (~checksum) & 0xFF;
state = ProcessState.CHECKSUM;
if (DEBUG) console.log("PREPARE CHECKSUM CHECK");
}
break;
// Validate the payload with the following checksum byte;
case ProcessState.CHECKSUM:
if (checksum == next_byte) {
if (DEBUG) console.log("CHECKSUM VALID");
// Checksum was valid, thus, processing packet given by the payload since is okay.
processPacket();
} else { // Pre-Condition: checksum != data
if (DEBUG) console.log("CHECKSUM IS WRONG [" + checksum + "!=" + next_byte + "]");
}
state = ProcessState.SYNC;
break;
default:
if (DEBUG) console.log("CRITICAL ERROR");
process.exit(1);
}
}
}
function processPacket() {
if (DEBUG) console.log("Process Packet");
// Create an empty EEG package.
var EEGPackage = {};
// Process all data rows in the received serial data package.
var payloadPointer = 0;
while (payloadPointer < payloadBuffer.length) {
// Determine the Extended Code Level (EXCODE) and CODE.
var extendedCodeLevel = 0;
var code;
while (payloadPointer < payloadBuffer.length) {
var next_byte = payloadBuffer.readUInt8(payloadPointer);
++payloadPointer;
if (next_byte == EXCODE) {
++extendedCodeLevel;
} else {
// The first byte unequal the EXCODE byte specifies the CODE.
code = next_byte;
break;
}
}
if (DEBUG) console.log ("extendedCodeLevel: " + extendedCodeLevel.toString(16) + ", code: " + code.toString(16));
if (extendedCodeLevel == 0) {
if (code <= 0x7F) { // Single-Byte CODEs
if (DEBUG) console.log ("Single-Byte CODE");
if (payloadPointer < payloadBuffer.length) {
var value = payloadBuffer.readUInt8(payloadPointer);
++payloadPointer;
// TODO: move to multi byte code
connect_timer = null;
switch (code) {
case CODE_ATTENTION:
EEGPackage["attention"] = value;
console.log ("ATTENTION: " + value);
break;
case CODE_MEDITATION:
EEGPackage["meditation"] = value;
console.log ("MEDITATION: " + value);
break;
default:
if (DEBUG) console.log ("DEFAULT: " + value);
}
} else {
if (DEBUG) console.log("CRITICAL ERROR");
process.exit(1);
}
} else { // Multi-Byte CODEs, Pre-Condition: code >= 0x80
if (DEBUG) console.log ("Multi-Byte CODE");
if (payloadPointer < payloadBuffer.length) {
var vlength = payloadBuffer.readUInt8(payloadPointer);
++payloadPointer;
if (DEBUG) console.log("payloadPointer: " + payloadPointer + ", vlength: " + vlength);
// Skip multi-byte data asap.
payloadPointer += vlength;
if (DEBUG) console.log("next payloadPointer: " + payloadPointer);
} else {
if (DEBUG) console.log("CRITICAL ERROR");
process.exit(1);
}
}
} else {
console.log("Not implemented!");
process.exit(1);
}
}
// Record/send the EEGPackage.
if (Object.getOwnPropertyNames(EEGPackage).length !== 0) {
var EEGPackage_JSON = JSON.stringify(EEGPackage);
// Send to clients listening via sockets.
io.emit('get-EEG', JSON.stringify(EEGPackage));
if (DEBUG) console.log(EEGPackage_JSON);
}
}
\ No newline at end of file
This diff is collapsed.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Whitney Music Box in HTML5</title>
<title>Custom Music Box</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<!-- midi.js package -->
<script src="./js/Color/SpaceW3.js" type="text/javascript"></script>
......@@ -17,6 +17,8 @@
<!-- extras -->
<script src="./inc/Base64.js" type="text/javascript"></script>
<script src="./inc/base64binary.js" type="text/javascript"></script>
<script src="https://cdn.socket.io/socket.io-1.3.2.js"></script>
<!-- font -->
<link href="http://fonts.googleapis.com/css?family=Andada" rel="stylesheet" type="text/css" />
<style>
......@@ -27,17 +29,37 @@
#wave {
width: 100%;
height: 600px;
height: 200px;
margin-bottom: 30px;
position: absolute;
top: 50%;
transform: translateY(-300px);
top: 10%;
/*transform: translateY(-150px);*/
}
#eegWave {
width: 100%;
height: 200px;
margin-bottom: 30px;
position: absolute;
top: 60%;
/*transform: translateY(150px);*/
}
h1 {
color: #fff;
}
</style>
</head>
<body>
<div id="wave"></div>
<div id="wave">
<h1>Soundwave</h1>
</div>
<div id="eegWave">
<h1>EEG Data: (Attention)</h1>
</div>
<script type="text/javascript">
......@@ -49,9 +71,9 @@ var PI2 = PI * 2;
var tines = [];
var lastSound = [];
var instrument = 0;
var data = [];
var eegData = [];
var waveform = new Waveform({
container: document.getElementById("wave"),
......@@ -65,16 +87,38 @@ gradient.addColorStop(1.0, "#ff1b00");
waveform.innerColor = gradient;
var eegWaveform = new Waveform({
container: document.getElementById("eegWave"),
interpolate: false
});
var ctx2 = eegWaveform.context;
var gradient2 = ctx2.createLinearGradient(0, 0, 0, eegWaveform.height);
gradient2.addColorStop(0.0, "#ff6");
gradient2.addColorStop(1.0, "#fff");
eegWaveform.innerColor = gradient2;
var instrument = 4;
RefreshFrame = function () {
var speed = (2 * PI * nbrPoints) / cycleLength;
var speed = (PI2 * nbrPoints) / cycleLength;
var ms = (new Date()).getTime();
var timer = (ms - startTime) * .001 * speed;
for (var i = 0; i < nbrPoints; ++i) {
var r = (i + 1) / nbrPoints;
var a = timer * r;
if (Math.floor(a / PI2) !== Math.floor(tines[i] / PI2)) {
MIDI.noteOn(instrument, i + 21, 100, 0);
MIDI.noteOn(instrument, i + 21 + 36, 100, 0);
delay = i / 4;
velocity = 127;
note = MIDI.pianoKeyOffset + i;
MIDI.noteOn(instrument, note, velocity, delay);
MIDI.noteOn(0, note, velocity, delay);
lastSound[i] = ms;
data.push(Math.cos(i/25) - 0.2 + r*0.3);
......@@ -86,21 +130,49 @@ RefreshFrame = function () {
}
};
var socket = io('http://localhost:3000');
socket.on('get-EEG', function (data) {
data = JSON.parse(data);
if (data.attention > 0 && data.meditation > 0) {
RefreshFrame();
var min_nbrPoints = 48;
var max_nbrPoints = 96;
var min_data = 0;
var max_data = 100;
nbrPoints = min_nbrPoints + ((max_nbrPoints - min_nbrPoints) * (data.attention - min_data)) / (max_data - min_data);
eegData.push(Math.cos(data.attention - 0.2 + 0.3));
eegWaveform.update({
data: eegData
});
} else {
eegData.push(Math.cos(90));
eegWaveform.update({
data: eegData
});
console.log('Connecting...')
}
});
window.onload = function () {
MIDI.loadPlugin({
soundfontUrl: "./soundfont/",
instruments: [ "acoustic_grand_piano", "synth_drum", "pad_2_warm"],
instruments: [
"acoustic_grand_piano",
"synth_drum",
"pad_2_warm",
"sitar",
"bright_acoustic_piano"
],
callback: function() {
MIDI.programChange(0, 0);
MIDI.programChange(1, 118);
MIDI.programChange(2, 89);
// for (var i = 0; i < nbrPoints; ++i) {
// if (i % 7 === 0) MIDI.noteOn(0, i + 21, 100, 0);
// lastSound[i] = 0;
// tines[i] = 0;
// }
// startTime = (new Date()).getTime();
setInterval(RefreshFrame, 200);
MIDI.programChange(3, 104);
MIDI.programChange(4, 1);
// setInterval(RefreshFrame, 200);
}
});
};
......
{
"name": "midi",
"version": "0.3.0",
"description": "Library to assist in creating HTML5 MIDI apps.",
"author": "Michael Deal",
"contributors": [
"Sergi Mansilla",
"Daniel van der Meer",
"Mohit Muthanna",
"Pete Otaqui"
],
"repository": {
"type": "git",
"url": "git://github.com/mudcube/MIDI.js.git"
"name": "webapp",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
},
"main": "./build/MIDI.min.js",
"author": "",
"license": "MIT",
"devDependencies": {
"grunt": "~0.4.0",
"grunt-contrib-concat": "~0.1.3",
"grunt-contrib-uglify": "~0.1.2"
"dependencies": {
"enum": "*",
"serialport": "^1.4.10",
"socket.io": "^1.3.2"
}
}
var app = require('http').createServer(handler)
var io = require('socket.io')(app);
var fs = require('fs');
app.listen(80);
function handler (req, res) {
res.writeHead(200);
res.write('hi');
res.end();
}
var this_socket = null;
var data = require('./data/record.json');
var i = 0;
function sendData() {
this_socket.emit('brain', data[i] );
i++;
}
io.on('connection', function (socket) {
i = 0;
this_socket = socket;
setInterval(sendData, 500);
});
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment