2023-04-27 15:30:31 +02:00
|
|
|
const osc = require('osc')
|
|
|
|
const midi = require('midi')
|
|
|
|
const Quat = require('quaternion');
|
|
|
|
|
|
|
|
// CC kanali za midi mapping (kanal, CC kanal)
|
2023-05-15 12:42:29 +02:00
|
|
|
const midiKanal = 176;
|
|
|
|
|
2023-05-15 14:03:53 +02:00
|
|
|
// CC kanali senzorjev
|
|
|
|
const midiKanalSenzor = {
|
|
|
|
1: 20,
|
|
|
|
2: 21,
|
|
|
|
3: 22
|
|
|
|
}
|
|
|
|
|
2023-05-15 12:42:29 +02:00
|
|
|
const senzorCCKanal = {
|
|
|
|
1: 75,
|
|
|
|
2: 76,
|
|
|
|
3: 77
|
|
|
|
}
|
|
|
|
|
|
|
|
const senzorCCMute = {
|
|
|
|
1: 78,
|
|
|
|
2: 79,
|
|
|
|
3: 80
|
|
|
|
}
|
|
|
|
|
|
|
|
const senzorCCkalibracija = {
|
|
|
|
1: 81,
|
|
|
|
2: 82,
|
|
|
|
3: 83
|
|
|
|
}
|
2023-04-27 15:30:31 +02:00
|
|
|
|
|
|
|
const DEBUG = {
|
2024-07-25 19:36:42 +02:00
|
|
|
midi: false,
|
2023-04-27 15:30:31 +02:00
|
|
|
osc: false
|
|
|
|
}
|
|
|
|
|
2024-07-25 21:29:02 +02:00
|
|
|
const batMin = 0.09
|
|
|
|
const batMax = 0.133
|
|
|
|
|
|
|
|
const procentBaterije = baterija => Math.round((baterija - batMin) / (batMax - batMin) * 100)
|
|
|
|
|
2023-04-27 15:30:31 +02:00
|
|
|
// Kalibracijsko izhodisce
|
2023-05-15 12:42:29 +02:00
|
|
|
const izhodisceQ = {
|
|
|
|
1: new Quat(),
|
|
|
|
2: new Quat(),
|
|
|
|
3: new Quat()
|
|
|
|
}
|
|
|
|
|
|
|
|
const prejsnjiQ = {
|
|
|
|
1: new Quat(),
|
|
|
|
2: new Quat(),
|
|
|
|
3: new Quat()
|
|
|
|
}
|
2023-04-27 15:30:31 +02:00
|
|
|
|
2023-05-15 12:42:29 +02:00
|
|
|
const eulerRotacija = {
|
|
|
|
1: [0, 0, 0],
|
|
|
|
2: [0, 0, 0],
|
|
|
|
3: [0, 0, 0]
|
|
|
|
}
|
2023-04-27 15:30:31 +02:00
|
|
|
|
2023-05-15 12:42:29 +02:00
|
|
|
const senzorCC = {
|
|
|
|
1: 64,
|
|
|
|
2: 64,
|
|
|
|
3: 64
|
|
|
|
}
|
2023-04-27 15:30:31 +02:00
|
|
|
|
2023-05-15 12:42:29 +02:00
|
|
|
let staroVrtenjeZMidi = {
|
|
|
|
1: 0,
|
|
|
|
2: 0,
|
|
|
|
3: 0
|
|
|
|
};
|
2023-04-27 15:30:31 +02:00
|
|
|
|
2023-05-15 12:42:29 +02:00
|
|
|
const muteMidi = {
|
|
|
|
1: 0,
|
|
|
|
2: 0,
|
|
|
|
3: 0
|
|
|
|
}
|
2023-05-08 11:40:37 +02:00
|
|
|
|
2024-07-25 19:36:42 +02:00
|
|
|
// Stetje prejetih paketov (na sekundo)
|
|
|
|
let cas = 0;
|
|
|
|
let baterija = 0;
|
|
|
|
let stPaketov = 0;
|
|
|
|
let stPaketovNaSekundo = 0;
|
|
|
|
|
2023-04-27 15:30:31 +02:00
|
|
|
// Midi controller input
|
|
|
|
const mi = new midi.Input()
|
|
|
|
mi.openVirtualPort("danijela-midi")
|
|
|
|
mi.on('message', (deltaTime, msg) => {
|
2023-05-15 12:42:29 +02:00
|
|
|
if (msg[0] === midiKanal) {
|
|
|
|
if (Object.values(senzorCCKanal).includes(msg[1])) {
|
|
|
|
const s = Object.values(senzorCCKanal).indexOf(msg[1]) + 1
|
|
|
|
if (!muteMidi[s]) {
|
2023-05-15 14:03:53 +02:00
|
|
|
senzorCC[s] = msg[2]
|
2023-05-15 12:42:29 +02:00
|
|
|
console.log(`senzor ${s}: ${msg[2]}`)
|
|
|
|
}
|
|
|
|
} else if (Object.values(senzorCCMute).includes(msg[1])) {
|
|
|
|
const s = Object.values(senzorCCMute).indexOf(msg[1]) + 1
|
|
|
|
if (msg[2]) {
|
|
|
|
console.log(`senzor UNMUTE ${s}`)
|
|
|
|
muteMidi[s] = false;
|
|
|
|
} else {
|
|
|
|
muteMidi[s] = true;
|
|
|
|
console.log(`senzor MUTE ${s}`)
|
|
|
|
}
|
|
|
|
} else if (Object.values(senzorCCkalibracija).includes(msg[1])) {
|
|
|
|
const s = Object.values(senzorCCkalibracija).indexOf(msg[1]) + 1
|
2024-08-22 17:39:59 +02:00
|
|
|
// resetiraj izhodisce quaterniona
|
2023-05-15 12:42:29 +02:00
|
|
|
izhodisceQ[s] = prejsnjiQ[s].conjugate()
|
2024-08-22 17:39:59 +02:00
|
|
|
// nastavi CC vrednost na sredino - 64
|
|
|
|
senzorCC[s] = 64;
|
2023-05-15 12:42:29 +02:00
|
|
|
console.log(`senzor KALIBRACIJA ${s}`)
|
|
|
|
}
|
2023-04-27 15:30:31 +02:00
|
|
|
}
|
|
|
|
|
2023-05-15 14:03:53 +02:00
|
|
|
//console.log(`midi in: ${msg} d: ${deltaTime}`);
|
2023-04-27 15:30:31 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
// Razpon za pospeskomerje
|
|
|
|
const accMin = -8000
|
|
|
|
const accMax = 8000
|
|
|
|
|
|
|
|
// Povezava na wavey wind
|
|
|
|
const ip = process.argv[2]
|
|
|
|
const oscWS = new osc.WebSocketPort({
|
|
|
|
url: `ws://${ip}:6676`,
|
|
|
|
metadata: false
|
|
|
|
})
|
|
|
|
|
|
|
|
oscWS.on('ready', () => {
|
|
|
|
console.log(`Povezan sem na ${ip}`)
|
|
|
|
|
2024-07-25 21:29:02 +02:00
|
|
|
// PING test!
|
|
|
|
if (DEBUG.ping) {
|
|
|
|
setInterval(() => {
|
|
|
|
console.log('ping')
|
|
|
|
oscWS.send({ address: '/ping', args: [true]})
|
|
|
|
}, 500)
|
|
|
|
}
|
2023-04-27 15:30:31 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
function posljiMidi(kanal, vrednost, jakost) {
|
2024-07-25 21:29:02 +02:00
|
|
|
DEBUG.midi && console.log('MIDI', kanal, vrednost, jakost)
|
2023-04-27 15:30:31 +02:00
|
|
|
|
|
|
|
oscWS.send({
|
|
|
|
address: '/midi',
|
|
|
|
args: [kanal, vrednost, jakost]
|
|
|
|
})
|
|
|
|
}
|
|
|
|
function posljiMidiCC(kanal, vrednost) {
|
2023-05-15 12:42:29 +02:00
|
|
|
posljiMidi(midiKanal, kanal, vrednost);
|
2023-04-27 15:30:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//const norm = (val, min, max) => Math.min(1, (val - min) / (max - min))
|
|
|
|
const norm = (val, min, max) => {
|
|
|
|
const d = 0 - min;
|
|
|
|
const r = max - min
|
|
|
|
return Math.min(1, (Math.max(min, val) + d) / r);
|
|
|
|
}
|
|
|
|
const normSin = val => {
|
|
|
|
return norm(Math.sin(val), -1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
const normMidi = (val, min, max) => Math.round(norm(val, min, max) * 127)
|
|
|
|
const abs = Math.abs;
|
|
|
|
|
|
|
|
let cakaj = false;
|
|
|
|
|
2024-07-25 21:31:31 +02:00
|
|
|
const izpisiStanje = (vrtenje, baterija, signali) => {
|
|
|
|
const vrstica = `| vrtenje: ${String(vrtenje).padStart(3, ' ')} | baterija: ${String(procentBaterije(baterija)).padStart(3, ' ')}% | signali/sekundo: ${signali}`
|
2024-07-25 21:29:02 +02:00
|
|
|
|
|
|
|
process.stdout.write(`${vrstica}\r`);
|
|
|
|
//process.stdout.moveCursor(vrstica.length + 1)
|
|
|
|
//process.stdout.clearLine(1)
|
|
|
|
}
|
|
|
|
|
2023-04-27 15:30:31 +02:00
|
|
|
oscWS.on('message', ({ address, args }) => {
|
|
|
|
DEBUG.osc && console.log('MSG OSC', address, args.map(x => x.toFixed(4)))
|
|
|
|
|
|
|
|
// Wavey Wind sporočila
|
|
|
|
const re = /\/ww\/0\/ww\/(\d+)\/([a-zA-Z]+)/
|
|
|
|
const m = address.match(re)
|
|
|
|
|
|
|
|
if (m) {
|
|
|
|
const index = parseInt(m[1])
|
|
|
|
const addr = m[2]
|
|
|
|
|
2024-07-25 19:36:42 +02:00
|
|
|
if (addr == 'bat') {
|
|
|
|
baterija = args[0]
|
2023-04-27 15:30:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (addr == 'accel') {
|
|
|
|
const acX = args[0]
|
|
|
|
const acY = args[1]
|
|
|
|
const acZ = args[2]
|
|
|
|
|
|
|
|
//console.log(acX, acY, acZ);
|
|
|
|
|
|
|
|
// CC sporocila!
|
|
|
|
/*
|
|
|
|
posljiMidiCC(20, normMidi(acX, accMin, accMax));
|
|
|
|
posljiMidiCC(21, normMidi(acY, accMin, accMax));
|
|
|
|
posljiMidiCC(22, normMidi(acZ, accMin, accMax));
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
if (addr == 'quaternion') {
|
2023-05-08 11:40:37 +02:00
|
|
|
//console.log('IDX', index)
|
2023-04-27 15:30:31 +02:00
|
|
|
// Izracunaj spremembo rotacije
|
2023-05-15 12:42:29 +02:00
|
|
|
const novQ = new Quat({w: args[0], x: args[1], y: args[2], z: args[3]})
|
|
|
|
const novQC = novQ.mul(izhodisceQ[index])
|
|
|
|
const qWd = novQC.div(prejsnjiQ[index])
|
2023-05-15 14:03:53 +02:00
|
|
|
prejsnjiQ[index] = novQC;
|
2023-04-27 15:30:31 +02:00
|
|
|
|
2023-05-15 14:03:53 +02:00
|
|
|
const eulerD = qWd.toEuler()
|
|
|
|
//console.log(index, eulerD)
|
2023-05-15 12:42:29 +02:00
|
|
|
eulerRotacija[index][0] += eulerD.roll * (senzorCC[index] / 64);
|
|
|
|
eulerRotacija[index][1] += eulerD.pitch * (senzorCC[index] / 64);
|
|
|
|
eulerRotacija[index][2] += eulerD.yaw * (senzorCC[index] / 64);
|
2023-04-27 15:30:31 +02:00
|
|
|
|
2023-05-15 12:42:29 +02:00
|
|
|
const vrtenjeX = Math.abs(Math.sin(eulerRotacija[index][0]));
|
2023-04-27 15:30:31 +02:00
|
|
|
/*
|
|
|
|
posljiMidi(180, 20, Math.round(vrtenjeX * 127));
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Roka dol/gor
|
2023-05-15 12:42:29 +02:00
|
|
|
const vrtenjeY = Math.abs(Math.sin(eulerRotacija[index][1]));
|
2023-04-27 15:30:31 +02:00
|
|
|
//posljiMidi(180, 20, Math.round(vrtenjeY * 127));
|
|
|
|
//posljiMidi(181, 20, Math.round(vrtenjeY * 127));
|
|
|
|
|
|
|
|
|
2023-05-15 12:42:29 +02:00
|
|
|
const vrtenjeZ = normSin(eulerRotacija[index][2])
|
2023-05-15 14:03:53 +02:00
|
|
|
const vrtenjeZmidi = Math.round(vrtenjeZ * 127)
|
2023-05-08 11:40:37 +02:00
|
|
|
|
2023-05-15 12:42:29 +02:00
|
|
|
if (vrtenjeZmidi !== staroVrtenjeZMidi[index]
|
|
|
|
&& !muteMidi[index]) {
|
2023-05-15 14:03:53 +02:00
|
|
|
posljiMidi(182, midiKanalSenzor[index], vrtenjeZmidi)
|
|
|
|
staroVrtenjeZMidi[index] = vrtenjeZmidi
|
2023-05-08 11:40:37 +02:00
|
|
|
}
|
2024-07-25 19:36:42 +02:00
|
|
|
|
|
|
|
// Vsako sekundo shranimo stevec
|
|
|
|
stPaketov += 1
|
|
|
|
if (Date.now() - cas > 1000) {
|
|
|
|
cas = Date.now()
|
|
|
|
stPaketovNaSekundo = stPaketov;
|
|
|
|
stPaketov = 0;
|
2024-07-25 21:29:02 +02:00
|
|
|
// 0.086 - 0.133 je razpon baterije
|
|
|
|
|
2024-07-25 19:36:42 +02:00
|
|
|
}
|
|
|
|
|
2024-07-25 21:31:31 +02:00
|
|
|
izpisiStanje(vrtenjeZmidi, baterija, stPaketovNaSekundo)
|
2023-04-27 15:30:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
oscWS.open()
|