Initial release
This commit is contained in:
105
view/assets/scripts/main.js
Normal file
105
view/assets/scripts/main.js
Normal file
@ -0,0 +1,105 @@
|
||||
if (!("controller" in window)) {
|
||||
let socket;
|
||||
|
||||
let volumeMeterLeft;
|
||||
let volumeMeterRight;
|
||||
|
||||
function connect(url) {
|
||||
if (socket) {
|
||||
socket.close();
|
||||
}
|
||||
|
||||
socket = new WebSocket(url);
|
||||
|
||||
socket.onmessage = function (event) {
|
||||
var data = JSON.parse(event.data);
|
||||
|
||||
switch (data.event) {
|
||||
case "device-list":
|
||||
if (data.data.devices.length > 0) {
|
||||
socket.send(JSON.stringify({
|
||||
"event": "open-device",
|
||||
"data": {
|
||||
"name": data.data.devices[0]
|
||||
}
|
||||
}));
|
||||
}
|
||||
break;
|
||||
case "signal":
|
||||
onSignal(event, data.data.name, data.data.value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
socket.onopen = function () {
|
||||
socket.send(JSON.stringify({
|
||||
"event": "load-driver",
|
||||
"data": {
|
||||
"name": "linux-rawmidi"
|
||||
}
|
||||
}));
|
||||
socket.send(JSON.stringify({
|
||||
"event": "load-mappings",
|
||||
"data": {
|
||||
"name": "numark-mixtrackplatinum"
|
||||
}
|
||||
}));
|
||||
socket.send(JSON.stringify({
|
||||
"event": "list-devices"
|
||||
}));
|
||||
};
|
||||
}
|
||||
|
||||
function sendControl(name, value = 0x00) {
|
||||
socket.send(JSON.stringify({
|
||||
"event": "control",
|
||||
"data": {
|
||||
"name": name,
|
||||
"value": value
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
window.controller = {
|
||||
"load": function (deckIndex) {
|
||||
sendControl("deck" + String(deckIndex) + ".load");
|
||||
},
|
||||
"play_pause": function (deckIndex) {
|
||||
sendControl("deck" + String(deckIndex) + ".play_pause");
|
||||
},
|
||||
"volume": function (deckIndex, value) {
|
||||
sendControl("deck" + String(deckIndex) + ".volume", value);
|
||||
},
|
||||
"speed": function (deckIndex, value) {
|
||||
sendControl("deck" + String(deckIndex) + ".speed", value);
|
||||
},
|
||||
"pad": function (deckIndex, padIndex) {
|
||||
sendControl("deck" + String(deckIndex) + ".pad" + String(padIndex));
|
||||
},
|
||||
"crossfade": function (value) {
|
||||
sendControl("master.crossfade", value);
|
||||
}
|
||||
};
|
||||
|
||||
var onSignal = function (event, name, value = 0x00) {
|
||||
switch (name) {
|
||||
case "master.volume.left":
|
||||
volumeMeterLeft.style.height = String(Math.round((value / 80) * 100)) + "%";
|
||||
break;
|
||||
case "master.volume.right":
|
||||
volumeMeterRight.style.height = String(Math.round((value / 80) * 100)) + "%";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
window.onload = function (event) {
|
||||
volumeMeterLeft = document.querySelector("#volume-meter-left");
|
||||
volumeMeterRight = document.querySelector("#volume-meter-right");
|
||||
|
||||
connect("ws://" + window.location.host + "/socket");
|
||||
};
|
||||
}
|
114
view/assets/stylesheets/style.css
Normal file
114
view/assets/stylesheets/style.css
Normal file
@ -0,0 +1,114 @@
|
||||
:root {
|
||||
--text-color: #FDFDFD;
|
||||
|
||||
background-color: rgba(8, 12, 16, 1.0);
|
||||
}
|
||||
|
||||
:root, body, main, #sections {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
button {
|
||||
min-width: 96px;
|
||||
min-height: 64px;
|
||||
}
|
||||
|
||||
#sections, .deck, #mixer, #volume, #volume-meters, .volume-meter, .deck-pads {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#sections, #volume, #volume-meters, .deck-pads {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#mixer, .deck {
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.deck {
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.reverse.deck {
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
#volume {
|
||||
/* flex-grow: 1; */
|
||||
}
|
||||
|
||||
.volume-slider, .speed-slider {
|
||||
appearance: slider-vertical !important;
|
||||
/* width: 8px;
|
||||
height: 100%; */
|
||||
}
|
||||
|
||||
.volume-meter {
|
||||
flex-direction: column-reverse;
|
||||
flex-grow: 1;
|
||||
background-image: linear-gradient(0deg, lime 0%, orange 80%, red 100%);
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
.volume-meter-level {
|
||||
width: 100%;
|
||||
background-color: white;
|
||||
mix-blend-mode: multiply;
|
||||
transition: height 0.05s ease-in-out;
|
||||
}
|
||||
|
||||
.silence-meter-level {
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
background-color: grey;
|
||||
mix-blend-mode: multiply;
|
||||
}
|
||||
|
||||
.deck-pads, .play {
|
||||
margin: 16px;
|
||||
}
|
||||
|
||||
.deck-pads {
|
||||
flex-wrap: wrap;
|
||||
width: 70%;
|
||||
aspect-ratio: 4 / 2;
|
||||
}
|
||||
|
||||
.deck-pad {
|
||||
width: 25%;
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
|
||||
/* input[type="range"] {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
input[type="range"]::-webkit-slider-thumb {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
background: var(--text-color);
|
||||
width: 16px;
|
||||
height: 48px;
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
input[type="range"]::-moz-range-thumb {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
background: var(--text-color);
|
||||
width: 16px;
|
||||
height: 48px;
|
||||
border-radius: 0px;
|
||||
} */
|
85
view/index.html
Normal file
85
view/index.html
Normal file
@ -0,0 +1,85 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>DJ Controller Emulator</title>
|
||||
|
||||
<link rel="stylesheet" href="assets/stylesheets/style.css">
|
||||
<script src="assets/scripts/main.js" charset="utf-8"></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div id="sections">
|
||||
<div class="deck">
|
||||
<div class="deck-effects">
|
||||
|
||||
</div>
|
||||
<div class="deck-playback">
|
||||
<input class="speed-slider" type="range" min="0" value="63" step="1" max="127" oninput="controller.speed(0, 127 - this.value);" ondblclick="controller.speed(0, this.value = 63);">
|
||||
</div>
|
||||
<div class="play">
|
||||
<div class="deck-pads">
|
||||
<button type="button" class="deck-pad" onclick="controller.pad(0, 0);"></button>
|
||||
<button type="button" class="deck-pad" onclick="controller.pad(0, 1);"></button>
|
||||
<button type="button" class="deck-pad" onclick="controller.pad(0, 2);"></button>
|
||||
<button type="button" class="deck-pad" onclick="controller.pad(0, 3);"></button>
|
||||
<button type="button" class="deck-pad" onclick="controller.pad(0, 4);"></button>
|
||||
<button type="button" class="deck-pad" onclick="controller.pad(0, 5);"></button>
|
||||
<button type="button" class="deck-pad" onclick="controller.pad(0, 6);"></button>
|
||||
<button type="button" class="deck-pad" onclick="controller.pad(0, 7);"></button>
|
||||
</div>
|
||||
<button type="button" onclick="controller.load(0);">Load</button>
|
||||
<button type="button" onclick="controller.play_pause(0);">PlayPause</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="mixer">
|
||||
<div id="knobs">
|
||||
<div class="deck-eq-knobs">
|
||||
|
||||
</div>
|
||||
<div class="deck-eq-knobs">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="volume">
|
||||
<input class="volume-slider" type="range" min="0" value="127" step="1" max="127" oninput="controller.volume(0, this.value);">
|
||||
<div id="volume-meters">
|
||||
<div class="volume-meter">
|
||||
<div id="volume-meter-left" class="volume-meter-level"></div>
|
||||
<div class="silence-meter-level"></div>
|
||||
</div>
|
||||
<div class="volume-meter">
|
||||
<div id="volume-meter-right" class="volume-meter-level"></div>
|
||||
<div class="silence-meter-level"></div>
|
||||
</div>
|
||||
</div>
|
||||
<input class="volume-slider" type="range" min="0" value="127" step="1" max="127" oninput="controller.volume(1, this.value);">
|
||||
</div>
|
||||
<input id="crossfader" type="range" min="0" value="63" step="1" max="127" oninput="controller.crossfade(this.value);">
|
||||
</div>
|
||||
<div class="reverse deck">
|
||||
<div class="deck-effects">
|
||||
|
||||
</div>
|
||||
<div class="deck-playback">
|
||||
<input class="speed-slider" type="range" min="0" value="63" step="1" max="127" oninput="controller.speed(1, 127 - this.value);" ondblclick="controller.speed(1, this.value = 63);">
|
||||
</div>
|
||||
<div class="play">
|
||||
<div class="deck-pads">
|
||||
<button type="button" class="deck-pad" onclick="controller.pad(1, 0);"></button>
|
||||
<button type="button" class="deck-pad" onclick="controller.pad(1, 1);"></button>
|
||||
<button type="button" class="deck-pad" onclick="controller.pad(1, 2);"></button>
|
||||
<button type="button" class="deck-pad" onclick="controller.pad(1, 3);"></button>
|
||||
<button type="button" class="deck-pad" onclick="controller.pad(1, 4);"></button>
|
||||
<button type="button" class="deck-pad" onclick="controller.pad(1, 5);"></button>
|
||||
<button type="button" class="deck-pad" onclick="controller.pad(1, 6);"></button>
|
||||
<button type="button" class="deck-pad" onclick="controller.pad(1, 7);"></button>
|
||||
</div>
|
||||
<button type="button" onclick="controller.load(1);">Load</button>
|
||||
<button type="button" onclick="controller.play_pause(1);">PlayPause</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user