diff --git a/anim.js b/anim.js index ab6aaa0..40bab12 100644 --- a/anim.js +++ b/anim.js @@ -17,7 +17,7 @@ var FOV = 90; var width = 6; // Limit stevila objektov -var obj_limit = 1000; +var obj_limit = 10; // Prvotno prazno polje objektov. Lahko bi kak buffer to bil pozneje var objekti = []; @@ -57,10 +57,14 @@ var qWWo = new THREE.Quaternion(-1, 0, 0, 0); var qWWd = new THREE.Quaternion(-1, 0, 0, 0); var qObj = new THREE.Quaternion(-1, 0, 0, 0); var qStart = new THREE.Quaternion(-1, 0, 0, 0); -var qCalibrate = new THREE.Quaternion(); var calibrate = true; var reset = false; +// Razlika v eulerjih +var dqX = 0; +var dqY = 0; +var dqZ = 0; + // Gumbi in pa pospesek var keysPressed = [0, 0, 0, 0]; var accel = [0, 0, 0]; @@ -128,8 +132,9 @@ function modulirajParametre() { drotacijaZ += qWWd.z / 10; } if (keysPressed[0]) { - width += qWWd.x * 10; - barva_mod += qWW.y / 10000; + width *= 1 + (dqY / 3); + barva_mod += (dqX / 30); + obj_limit *= 1 + (dqZ / 3); } } @@ -226,14 +231,134 @@ function onWindowResize() { window.addEventListener('resize', onWindowResize, false); -const getVal = function (msg) { +function getVal(msg) { return msg.value; } -oscCallbacks = { +kbdPressed = { + a: false, + s: false, + d: false, + f: false +}; + +window.addEventListener('keydown', (e) => { + kbdPressed[e.key] = true; +}) + +window.addEventListener('keyup', (e) => { + if (e.key in kbdPressed) { + kbdPressed[e.key] = false; + } +}) + +function eulerFromQuaternion( quaternion, order ) { + // Quaternion to matrix. + const w = quaternion[0], x = quaternion[1], y = quaternion[2], z = quaternion[3]; + const x2 = x + x, y2 = y + y, z2 = z + z; + const xx = x * x2, xy = x * y2, xz = x * z2; + const yy = y * y2, yz = y * z2, zz = z * z2; + const wx = w * x2, wy = w * y2, wz = w * z2; + const matrix = [ + 1 - ( yy + zz ), + xy + wz, + xz - wy, + 0, + xy - wz, + 1 - ( xx + zz ), + yz + wx, + 0, + xz + wy, + yz - wx, + 1 - ( xx + yy ), + 0, + 0, + 0, + 0, + 1 + ]; + // Matrix to euler + function clamp( value, min, max ) { + return Math.max( min, Math.min( max, value ) ); + } + const m11 = matrix[ 0 ], m12 = matrix[ 4 ], m13 = matrix[ 8 ]; + const m21 = matrix[ 1 ], m22 = matrix[ 5 ], m23 = matrix[ 9 ]; + const m31 = matrix[ 2 ], m32 = matrix[ 6 ], m33 = matrix[ 10 ]; + var euler = [ 0, 0, 0 ]; + switch ( order ) { + case "XYZ": + euler[1] = Math.asin( clamp( m13, - 1, 1 ) ); + if ( Math.abs( m13 ) < 0.9999999 ) { + euler[0] = Math.atan2( - m23, m33 ); + euler[2] = Math.atan2( - m12, m11 ); + } else { + euler[0] = Math.atan2( m32, m22 ); + euler[2] = 0; + } + break; + case "YXZ": + euler[0] = Math.asin( - clamp( m23, - 1, 1 ) ); + if ( Math.abs( m23 ) < 0.9999999 ) { + euler[1] = Math.atan2( m13, m33 ); + euler[2] = Math.atan2( m21, m22 ); + } else { + euler[1] = Math.atan2( - m31, m11 ); + euler[2] = 0; + } + break; + case "ZXY": + euler[0] = Math.asin( clamp( m32, - 1, 1 ) ); + if ( Math.abs( m32 ) < 0.9999999 ) { + euler[1] = Math.atan2( - m31, m33 ); + euler[2] = Math.atan2( - m12, m22 ); + } else { + euler[1] = 0; + euler[2] = Math.atan2( m21, m11 ); + } + break; + case "ZYX": + euler[1] = Math.asin( - clamp( m31, - 1, 1 ) ); + if ( Math.abs( m31 ) < 0.9999999 ) { + euler[0] = Math.atan2( m32, m33 ); + euler[2] = Math.atan2( m21, m11 ); + } else { + euler[0] = 0; + euler[2] = Math.atan2( - m12, m22 ); + } + break; + case "YZX": + euler[2] = Math.asin( clamp( m21, - 1, 1 ) ); + if ( Math.abs( m21 ) < 0.9999999 ) { + euler[0] = Math.atan2( - m23, m22 ); + euler[1] = Math.atan2( - m31, m11 ); + } else { + euler[0] = 0; + euler[1] = Math.atan2( m13, m33 ); + } + break; + case "XZY": + euler[2] = Math.asin( - clamp( m12, - 1, 1 ) ); + if ( Math.abs( m12 ) < 0.9999999 ) { + euler[0] = Math.atan2( m32, m22 ); + euler[1] = Math.atan2( m13, m11 ); + } else { + euler[0] = Math.atan2( - m23, m33 ); + euler[1] = 0; + } + break; + } + return euler; +} + +var oscCallbacks = { '/keys/': [ function(args) { keysPressed = args.map(getVal); + keysPressed[0] |= kbdPressed['a']; + keysPressed[1] |= kbdPressed['s']; + keysPressed[2] |= kbdPressed['d']; + keysPressed[3] |= kbdPressed['f']; + //console.log(keysPressed, kbdPressed); } ], '/quaternion/': [ @@ -247,6 +372,11 @@ oscCallbacks = { qWWd = qWW.clone(); qWWd.conjugate(); qWWd.multiply(qWWo); + + var euler = eulerFromQuaternion([qWWd.w, qWWd.z, qWWd.x, qWWd.y], 'XYZ'); + dqX = euler[0]; + dqY = euler[1]; + dqZ = euler[2]; } ], /* diff --git a/scosc2.scd b/scosc2.scd index 1a8f263..92783b5 100644 --- a/scosc2.scd +++ b/scosc2.scd @@ -1,15 +1,39 @@ s.boot(); -~gW = 0; +( +~gW = -1; ~gX = 0; ~gY = 0; ~gZ = 0; +~dgW = -1; +~dgX = 0; +~dgY = 0; +~dgZ = 0; + +~oW = -1; +~oX = 0; +~oY = 0; +~oZ = 0; + +~euler; + +~calibrate = true; + +~quaternionToEuler = { |q| + var euler = Array.newClear(3); + euler[0] = atan2( (2 * q[1] * q[2]) - (2 * q[0] * q[3]), (2 * q[0]*q[0]) + (2 * q[1] * q[1]) - 1); // psi + euler[1] = asin( (2 * q[1] * q[3]) + (2 * q[0] * q[2])).neg; // theta + euler[2] = atan2( (2 * q[2] * q[3]) - (2 * q[0] * q[1]), (2 * q[0] * q[0]) + (2 * q[3] * q[3]) - 1); // phi + euler.raddeg + } +) + ( z = { arg f=440, amp=1, phase=0; var so; - so = SinOsc.ar(f, phase) * amp; + so = VarSaw.ar(f, phase) * amp; }.play; ) @@ -17,23 +41,90 @@ z = { y = { arg f=440, amp=1, phase=0; var so; - so = SinOsc.ar(f, phase) * amp; + so = VarSaw.ar(f, phase) * amp; }.play; ) +( +w = { + arg fa=1, fb=1, fc=1; + var so; + so = VarSaw.ar(LFPulse.kr(fa, 0, 0.3, 200 * fb, 200 * fc), 0, 0.2, 0.1) +}.play; +); + + // WW // Receiver function ( o = OSCFunc({ arg msg, time, addr, recvPort; + + ~oW = ~gW; + ~oX = ~gX; + ~oY = ~gY; + ~oZ = ~gZ; + //[msg, time, addr, recvPort].postln; - ~gX = msg[1]; - ~gY = msg[2]; - ~gZ = msg[3]; - ~gW = msg[0]; - z.set(\f, ~gX * 800); - y.set(\f, ~gY * 800); - y.set(\phase, ~gZ); + ~gW = msg[1]; + ~gZ = msg[2]; + ~gX = msg[3]; + ~gY = msg[0]; + + ~gX = ~gX * -1; + ~gZ = ~gZ * -1; + //z.set(\f, ~gX * 800); + //y.set(\f, ~gY * 800); + //y.set(\phase, ~gZ); + //w.set(\f1, ~gX); + //w.set(\f2, ~gY); + //w.set(\f3, ~gZ); + + ~dgW = ~gW; + ~dgX = -1 * ~gX; + ~dgY = -1 * ~gY; + ~dgZ = -1 * ~gZ; + + ~dgW = (~dgW * ~oW) - (~dgX * ~oX) - (~oY * ~oY) - (~dgZ * ~oZ); + ~dgX = (~dgW * ~oX) - (~dgX * ~oW) - (~dgY * ~oZ) - (~dgZ * ~oY); + ~dgY = (~dgW * ~oY) - (~dgX * ~oZ) - (~dgY * ~oW) - (~dgZ * ~oX); + ~dgZ = (~dgW * ~oZ) - (~dgX * ~oY) - (~dgY * ~oX) - (~dgZ * ~oW); + + ~euler = ~quaternionToEuler.([~dgW, ~dgX, ~dgY, ~dgZ]); + ~euler.postln; }, '/quaternion/', n); ) -// ENDWW \ No newline at end of file +// ENDWW + + + + + + + +MIDIClient.init; + +MIDIFunc.trace(false); +( +MIDIdef(\tMidi, { + arg msg; + msg.postln; + z.set(\f, msg * 100); +}, 10, 0, \control) +) + +( +MIDIdef(\tMidi, { + arg msg; + msg.postln; + z.set(\fb, msg); +}, 11, 0, \control) +) + +( +MIDIdef(\tMidi, { + arg msg; + msg.postln; + z.set(\fc, msg); +}, 12, 0, \control) +) \ No newline at end of file diff --git a/server.js b/server.js index bae9bfc..c79a6a9 100644 --- a/server.js +++ b/server.js @@ -114,10 +114,12 @@ function openBT() { }) } -if (baudrate) { - openSerial(baudrate) -} else { - openBT() +if (tty) { + if (baudrate) { + openSerial(baudrate) + } else { + openBT() + } } app.get('/', (req, res) => { @@ -149,12 +151,23 @@ server.listen(port, () => console.log('listening on *:' + port)) const wss = new WebSocket.Server({ server }) const scudp = new osc.UDPPort({ - remoteAddr: '127.0.0.1', - remotePort: 57120 + multicastMembership: ['224.0.1.9'], + remotePort: 6696, + multicastTTL: 10, + metadata: true }) scudp.on('open', () => { console.log("UDP to OSC open") }) +scudp.on('message', (msg) => { + console.log('got UDP msg', msg); + osclients.forEach( client => { + if (client) { + //console.log("sending", msg, info) + client.send(msg) + } + }) +}) scudp.open() const sendAll = (msg, info, oscWS, osclients) => {