diff --git a/plugins/x32/main.js b/plugins/x32/main.js index 4d41dda..81b4a8c 100644 --- a/plugins/x32/main.js +++ b/plugins/x32/main.js @@ -6,7 +6,7 @@ exports.searchOptions = { searchBuffer: Buffer.from([0x2f, 0x78, 0x69, 0x6e, 0x66, 0x6f]), devicePort: 10023, listenPort: 0, - validateResponse (msg, info) { + validateResponse(msg, info) { return msg.toString().indexOf('/xinfo') === 0; }, }; @@ -14,21 +14,10 @@ exports.defaultPort = 10023; exports.ready = function ready(device) { const d = device; - d.data.channelFaders = new Array(32).fill(0); - d.data.channelFadersDB = new Array(32).fill(0); - d.data.channelMutes = new Array(32).fill(0); - d.data.channelNames = new Array(32).fill('end'); - d.data.channelColors = new Array(32); - - d.data.stereoFader = 0; - d.data.stereoFaderDB = 0; - d.data.stereoMute = 0; + d.data.X32 = new Console(); d.send(Buffer.from('/xinfo')); - // device.send(Buffer.from("\x2f\x62\x61\x74\x63\x68\x73\x75\x62\x73\x63\x72\x69\x62\x65\x00\x2c\x73\x73\x69\x69\x69\x00\x00\x6d\x65\x74\x65\x72\x73\x2f\x30\x00\x00\x00\x00\x2f\x6d\x65\x74\x65\x72\x73\x2f\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01")); - // device.send(Buffer.from("/batchsubscribe\x00,ssiii\x00\x00meters/0\x00\x00\x00\x00/meters/0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01")); - // device.send(Buffer.from("/subscribe\x00,si\x00/-stat/solosw/01\x001")); }; @@ -38,59 +27,75 @@ function parseAddress(msg) { return addr; } -function convertToDBTheBehringerWay(f) { - if (f >= 0.5) { - return f * 40 - 30; - } - if (f >= 0.25) { - return f * 80 - 50; - } - if (f >= 0.0625) { - return f * 160 - 70; - } - return f * 480 - 90; -} - exports.data = function data(device, buf) { this.deviceInfoUpdate(device, 'status', 'ok'); - const msg = buf.toString().split('\u0000\u0000'); + + // replace one or more nulls with new line then split on that + const msg = buf.toString().replace(/(\0+)/gm, '\n').split('\n'); + const d = device; if (msg[0] === '/xinfo') { - this.deviceInfoUpdate(device, 'defaultName', msg[4]); - d.data.name = msg[4]; - d.data.ip = msg[2]; - d.data.firmware = msg[7]; - d.data.model = msg[5]; + d.data.X32.info.name = msg[3]; + d.data.X32.info.ip = msg[2]; + d.data.X32.info.firmware = msg[5]; + d.data.X32.info.model = msg[4]; - d.send(Buffer.from('/lr/mix/fader\u0000\u0000\u0000\u0000')); - d.send(Buffer.from('/lr/mix/on\u0000\u0000\u0000\u0000')); + this.deviceInfoUpdate(device, 'defaultName', d.data.X32.info.name); + + d.send(Buffer.from('/main/st/config/name\x00\x00\x00\x00')); for (let i = 0; i <= 32; i++) { d.send( Buffer.from( - `/ch/${i - .toString() - .padStart(2, '0')}/config/name\u0000\u0000\u0000\u0000` + `/ch/${i.toString().padStart(2, '0')}/config/name\x00\x00\x00\x00` ) ); } d.draw(); - } else if (msg[0] === '/meters/0') { - // console.log(msg) + } else if (msg[0].includes('meters/0')) { + let offset = 24; + for (let i = 0; i < 70; i++) { + if (i >= 0 && i < 32) { + // These are channel meters + d.data.X32.inputs.channels[i].meter = Console.getBehringerDB( + buf.readFloatLE(offset) + ); + } + + offset += 4; + } + d.draw(); + } else if (msg[0].includes('meters/2')) { + let offset = 24; + + for (let i = 0; i < 49; i++) { + if (i === 22) { + // STEREO LEFT METER + d.data.X32.main.stereo.meter[0] = Console.getBehringerDB( + buf.readFloatLE(offset) + ); + } else if (i === 23) { + // STEREO RIGHT METER + d.data.X32.main.stereo.meter[1] = Console.getBehringerDB( + buf.readFloatLE(offset) + ); + } + offset += 4; + } } else if (msg[0].indexOf('/mix/fader') >= 0) { const addr = parseAddress(msg[0]); const channel = Number(addr[1]); if (addr[0] === 'ch') { - d.data.channelFaders[channel - 1] = buf.readFloatBE(24); - d.data.channelFadersDB[channel - 1] = convertToDBTheBehringerWay( + d.data.X32.inputs.channels[channel - 1].fader = buf.readFloatBE(24); + d.data.X32.inputs.channels[channel - 1].faderDB = Console.getBehringerDB( buf.readFloatBE(24) ); - } else if (addr[0] === 'lr') { - d.data.stereoFader = buf.readFloatBE(20); - d.data.stereoFaderDB = convertToDBTheBehringerWay( - buf.readFloatBE(20) + } else if (addr[0] === 'main') { + d.data.X32.main.stereo.fader = buf.readFloatBE(24); + d.data.X32.main.stereo.faderDB = Console.getBehringerDB( + buf.readFloatBE(24) ); } @@ -100,28 +105,40 @@ exports.data = function data(device, buf) { const channel = Number(addr[1]); if (addr[0] === 'ch') { - d.data.channelMutes[channel - 1] = buf[23]; - } else if (addr[0] === 'lr') { - d.data.stereoMute = buf[19]; + d.data.X32.inputs.channels[channel - 1].mute = buf[23]; + d.send(Buffer.from(`/ch/${addr[1]}/mix/fader\x00\x00\x00\x00`)); + } else if (addr[0] === 'main') { + d.data.X32.main.stereo.mute = buf.slice(-1)[0]; + d.send(Buffer.from(`/main/${addr[1]}/mix/fader\x00\x00\x00\x00`)); } d.draw(); - d.send( - Buffer.from(`/ch/${addr[1]}/mix/fader\u0000\u0000\u0000\u0000`) - ); } else if (msg[0].indexOf('/config/name') > 0) { const addr = parseAddress(msg[0]); - const channel = Number(addr[1]); - d.data.channelNames[channel - 1] = msg[2]; + if (addr[0] === 'main') { + if (addr[1] === 'st') { + d.data.X32.main.stereo.name = msg[2]; + if (d.data.X32.main.stereo.name === '') { + d.data.X32.main.stereo.name = 'LR'; + } + d.send(Buffer.from(`/main/${addr[1]}/config/color\x00\x00\x00\x00`)); + } + } else if (addr[0] === 'ch') { + const channel = Number(addr[1]); + d.data.X32.inputs.channels[channel - 1].name = msg[2]; + d.send(Buffer.from(`/ch/${addr[1]}/config/color\x00\x00\x00\x00`)); + } d.draw(); - d.send( - Buffer.from(`/ch/${addr[1]}/config/color\u0000\u0000\u0000\u0000`) - ); } else if (msg[0].indexOf('/config/color') > 0) { const addr = parseAddress(msg[0]); - const channel = Number(addr[1]); - d.data.channelColors[channel - 1] = buf.readInt8(27); + if (addr[0] === 'main') { + d.data.X32.main.stereo.color = Buffer.from(msg[2]).readInt8(); + d.send(Buffer.from(`/main/${addr[1]}/mix/on\x00\x00\x00\x00`)); + } else if (addr[0] === 'ch') { + const channel = Number(addr[1]); + d.data.X32.inputs.channels[channel - 1].color = buf.readInt8(27); + d.send(Buffer.from(`/ch/${addr[1]}/mix/on\x00\x00\x00\x00`)); + } d.draw(); - d.send(Buffer.from(`/ch/${addr[1]}/mix/on\u0000\u0000\u0000\u0000`)); } else { // console.log(msg) } @@ -130,4 +147,63 @@ exports.data = function data(device, buf) { exports.heartbeat = function heartbeat(device) { device.send(Buffer.from('/xremote')); + + // subscribe to meter groups + device.send( + Buffer.from( + '/batchsubscribe\x00,ssiii\x00\x00meters/0\x00\x00\x00\x00/meters/0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' + ) + ); + device.send( + Buffer.from( + '/batchsubscribe\x00,ssiii\x00\x00meters/2\x00\x00\x00\x00/meters/2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01' + ) + ); }; + +class Console { + constructor() { + this.inputs = { + channels: new Array(32).fill(0).map(() => ({ + fader: 0, + faderDB: 0, + mute: 0, + name: 'end', + color: undefined, + meter: -90, + })), + }; + + this.main = { + stereo: { + fader: 0, + faderDB: 0, + mute: 0, + name: 'LR', + color: 7, + meter: new Array(2).fill(-90), + }, + }; + + this.info = { + name: '', + ip: '', + firmware: '', + model: '', + }; + } + + static getBehringerDB(level) { + const f = level; + if (f >= 0.5) { + return f * 40 - 30; + } + if (f >= 0.25) { + return f * 80 - 50; + } + if (f >= 0.0625) { + return f * 160 - 70; + } + return f * 480 - 90; + } +} diff --git a/plugins/x32/styles.css b/plugins/x32/styles.css index 02b7788..8282031 100644 --- a/plugins/x32/styles.css +++ b/plugins/x32/styles.css @@ -128,3 +128,29 @@ input[type='range']::-webkit-slider-runnable-track { background: #3b3b3b; border-radius: 4px; } + +.infin { + font-size: 20px; + vertical-align: middle; +} + +.meter { + height: 3px; + background: linear-gradient( + 90deg, + rgba(19, 126, 30, 1) 0%, + rgba(255, 238, 30, 1) 85%, + rgba(255, 0, 0, 1) 100% + ); +} + +/* need to find a way to match the color of this with the table row */ +.meter-cover { + height: 100%; + background-color: rgb(22, 23, 25); + float: right; +} + +table.cv-table tr:nth-child(odd) td div.meter div.meter-cover { + background-color: #292929; +} diff --git a/plugins/x32/template.ejs b/plugins/x32/template.ejs index c0f95c1..cd6baf8 100644 --- a/plugins/x32/template.ejs +++ b/plugins/x32/template.ejs @@ -13,39 +13,51 @@ LR -
MAIN OUT
-
M
- <%- formatAsDB(data.stereoFaderDB) %> +
<%- data.X32.main.stereo.name%>
+
M
+ <%= formatAsDB(data.X32.main.stereo.faderDB) %> + <% let style = `style=width:${Math.abs(data.X32.main.stereo.meter[0] - 10)}%`; %> +
+
>
+
+ <% style = `style=width:${Math.abs(data.X32.main.stereo.meter[1] - 10)}%`; %> +
+
>
+
- <% for(var i=0; i<32; i++){ %> <% if(data.channelNames[i]=="end"){break;} %> + <% for(var i=0; i<32; i++){ %> <% if(data.X32.inputs.channels[i].name == "end"){break;} %> <%= i+1 %> -
- <%- data.channelNames[i] || i+1 %> +
+ <%- data.X32.inputs.channels[i].name || i+1 %>
-
M
- <%- formatAsDB(data.channelFadersDB[i]) %> +
M
+ <%= formatAsDB(data.X32.inputs.channels[i].faderDB) %> + <% let style = `style=width:${Math.abs(data.X32.inputs.channels[i].meter - 10)}%`; %> +
+
>
+
<% } %> -<% function formatAsDB(val){ if(val==-90){ return "-∞"; } if(val>0){ +<% function formatAsDB(val){ if(val==-90){ return '-'; } if(val>0){ return "+"+val.toFixed(1); } return val.toFixed(1); } %> diff --git a/plugins/xair/main.js b/plugins/xair/main.js index 3c759c7..152dd84 100644 --- a/plugins/xair/main.js +++ b/plugins/xair/main.js @@ -6,7 +6,7 @@ exports.searchOptions = { searchBuffer: Buffer.from([0x2f, 0x78, 0x69, 0x6e, 0x66, 0x6f]), devicePort: 10024, listenPort: 0, - validateResponse (msg, info) { + validateResponse(msg, info) { return msg.toString().indexOf('/xinfo') === 0; }, }; @@ -28,7 +28,6 @@ exports.ready = function ready(device) { // device.send(Buffer.from("\x2f\x62\x61\x74\x63\x68\x73\x75\x62\x73\x63\x72\x69\x62\x65\x00\x2c\x73\x73\x69\x69\x69\x00\x00\x6d\x65\x74\x65\x72\x73\x2f\x30\x00\x00\x00\x00\x2f\x6d\x65\x74\x65\x72\x73\x2f\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01")); // device.send(Buffer.from("/batchsubscribe\x00,ssiii\x00\x00meters/0\x00\x00\x00\x00/meters/0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01")); - // device.send(Buffer.from("/subscribe\x00,si\x00/-stat/solosw/01\x001")); }; @@ -53,7 +52,7 @@ function convertToDBTheBehringerWay(f) { exports.data = function data(device, buf) { this.deviceInfoUpdate(device, 'status', 'ok'); - const msg = buf.toString().split('\u0000'); + const msg = buf.toString().split('\x00'); const d = device; if (msg[0] === '/xinfo') { @@ -68,20 +67,17 @@ exports.data = function data(device, buf) { d.data.model = msg[9]; this.deviceInfoUpdate(d, 'defaultName', d.data.name); - d.send('/lr/mix/fader\u0000\u0000\u0000\u0000'); - d.send('/lr/mix/on\u0000\u0000\u0000\u0000'); + d.send('/lr/mix/fader\x00\x00\x00\x00'); + d.send('/lr/mix/on\x00\x00\x00\x00'); for (let i = 0; i <= 32; i++) { d.send( Buffer.from( - `/ch/${i - .toString() - .padStart(2, '0')}/config/name\u0000\u0000\u0000\u0000` + `/ch/${i.toString().padStart(2, '0')}/config/name\x00\x00\x00\x00` ) ); } d.draw(); - } else if (msg[0] === '/meters/0') { // console.log(msg) } else if (msg[0].indexOf('/mix/fader') >= 0) { @@ -95,13 +91,10 @@ exports.data = function data(device, buf) { ); } else if (addr[0] === 'lr') { d.data.stereoFader = buf.readFloatBE(20); - d.data.stereoFaderDB = convertToDBTheBehringerWay( - buf.readFloatBE(20) - ); + d.data.stereoFaderDB = convertToDBTheBehringerWay(buf.readFloatBE(20)); } d.draw(); - } else if (msg[0].indexOf('/mix/on') >= 0) { const addr = parseAddress(msg[0]); const channel = Number(addr[1]); @@ -112,22 +105,19 @@ exports.data = function data(device, buf) { d.data.stereoMute = buf[19]; } device.draw(); - device.send(`/ch/${addr[1]}/mix/fader\u0000\u0000\u0000\u0000`); - + device.send(`/ch/${addr[1]}/mix/fader\x00\x00\x00\x00`); } else if (msg[0].indexOf('/config/name') > 0) { const addr = parseAddress(msg[0]); const channel = Number(addr[1]); d.data.channelNames[channel - 1] = msg[4]; d.draw(); - d.send(`/ch/${addr[1]}/config/color\u0000\u0000\u0000\u0000`); - + d.send(`/ch/${addr[1]}/config/color\x00\x00\x00\x00`); } else if (msg[0].indexOf('/config/color') > 0) { const addr = parseAddress(msg[0]); const channel = Number(addr[1]); d.data.channelColors[channel - 1] = buf.readInt8(27); d.draw(); - d.send(`/ch/${addr[1]}/mix/on\u0000\u0000\u0000\u0000`); - + d.send(`/ch/${addr[1]}/mix/on\x00\x00\x00\x00`); } else { // console.log(msg) } diff --git a/plugins/xair/styles.css b/plugins/xair/styles.css index 1f25d39..06544f5 100644 --- a/plugins/xair/styles.css +++ b/plugins/xair/styles.css @@ -127,3 +127,8 @@ input[type='range']::-webkit-slider-runnable-track { background: #3b3b3b; border-radius: 4px; } + +.infin{ + font-size: 20px; + vertical-align: middle; +} diff --git a/plugins/xair/template.ejs b/plugins/xair/template.ejs index c0f95c1..6e8683e 100644 --- a/plugins/xair/template.ejs +++ b/plugins/xair/template.ejs @@ -15,7 +15,7 @@ LR
MAIN OUT
M
- <%- formatAsDB(data.stereoFaderDB) %> + <%= formatAsDB(data.stereoFaderDB) %>
M
- <%- formatAsDB(data.channelFadersDB[i]) %> + <%= formatAsDB(data.channelFadersDB[i]) %> -<% function formatAsDB(val){ if(val==-90){ return "-∞"; } if(val>0){ +<% function formatAsDB(val){ if(val==-90){ return '-'; } if(val>0){ return "+"+val.toFixed(1); } return val.toFixed(1); } %>