asd
This commit is contained in:
parent
53a6052375
commit
8683ea17a3
17
.vscode/launch.json
vendored
Normal file
17
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
// Verwendet IntelliSense zum Ermitteln möglicher Node.js-Debugattribute.
|
||||||
|
// Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen.
|
||||||
|
// Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "node",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Programm starten",
|
||||||
|
"program": "${workspaceRoot}/lib/timec.js",
|
||||||
|
"outFiles": [
|
||||||
|
"${workspaceRoot}/out/**/*.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
11
.vscode/tasks.json
vendored
Normal file
11
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
"version": "0.1.0",
|
||||||
|
"command": "tsc",
|
||||||
|
"isShellCommand": true,
|
||||||
|
"args": ["-w", "-p", "."],
|
||||||
|
"showOutput": "silent",
|
||||||
|
"isBackground": true,
|
||||||
|
"problemMatcher": "$tsc-watch"
|
||||||
|
}
|
0
concept.md
Normal file
0
concept.md
Normal file
20
db.json
20
db.json
@ -8,5 +8,25 @@
|
|||||||
"name": "test",
|
"name": "test",
|
||||||
"value": "5"
|
"value": "5"
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"3d47edcdc882": {
|
||||||
|
"displayName": "test",
|
||||||
|
"id": "3d47edcdc882",
|
||||||
|
"triggers": [
|
||||||
|
{
|
||||||
|
"midi": {
|
||||||
|
"channel": 1,
|
||||||
|
"note": 3,
|
||||||
|
"value": 4
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"lframe": 15,
|
||||||
|
"lseconds": 5,
|
||||||
|
"lminutes": 0,
|
||||||
|
"lhours": 0,
|
||||||
|
"lmilliseconds": 5600
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
}
|
186
index.js
186
index.js
@ -1,186 +0,0 @@
|
|||||||
var low = require("lowdb");
|
|
||||||
var db = low("db.json");
|
|
||||||
var sid = require("short-id");
|
|
||||||
sid.configure({length:12});
|
|
||||||
db.defaults({}).write();
|
|
||||||
|
|
||||||
var http = require("http").createServer();
|
|
||||||
|
|
||||||
var ioClient = require("socket.io-client")("http://localhost:5000");
|
|
||||||
var io = require("socket.io")(http);
|
|
||||||
|
|
||||||
var activeFile = undefined;
|
|
||||||
var toTrigger = [];
|
|
||||||
|
|
||||||
class FrameTime{
|
|
||||||
constructor(millis){
|
|
||||||
this.lframe = 0;
|
|
||||||
this.lseconds = 0;
|
|
||||||
this.lminutes = 0;
|
|
||||||
this.lhours = 0;
|
|
||||||
this.lmilliseconds = 0;
|
|
||||||
if(Number.isInteger(millis)){
|
|
||||||
this.milliseconds = millis;
|
|
||||||
} else if(typeof millis === "object"){
|
|
||||||
if(Number.isInteger(millis.frame) && Number.isInteger(millis.seconds) && Number.isInteger(millis.minutes) && Number.isInteger(millis.hours) ){
|
|
||||||
this.lframe = millis.frame; //use the local, because its mor performant
|
|
||||||
this.lseconds = milllis.seconds;
|
|
||||||
this.lminutes = millis.minutes;
|
|
||||||
this.lhours = millis.hours;
|
|
||||||
this.calcMillis();
|
|
||||||
} else if(Number.isInteger(millis.milliseconds)){
|
|
||||||
this.milliseconds = millis.milliseconds;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get milliseconds() {
|
|
||||||
return this.lmilliseconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
set milliseconds(val) {
|
|
||||||
this.lmilliseconds = val;
|
|
||||||
millisToFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
get frame(){
|
|
||||||
return this.lframe;
|
|
||||||
}
|
|
||||||
|
|
||||||
set frame (val) {
|
|
||||||
this.lframe = val;
|
|
||||||
calcMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
get seconds() {
|
|
||||||
return this.lseconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
set seconds(val){
|
|
||||||
this.lseconds = val;
|
|
||||||
calcMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
get minutes() {
|
|
||||||
return this.lminutes;
|
|
||||||
}
|
|
||||||
|
|
||||||
set minutes(val) {
|
|
||||||
this.lminutes = val;
|
|
||||||
calcMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
get hours(){
|
|
||||||
return this.lhours;
|
|
||||||
}
|
|
||||||
|
|
||||||
set hours(val){
|
|
||||||
this.lhours = val;
|
|
||||||
calcMillis();
|
|
||||||
}
|
|
||||||
|
|
||||||
calcMillis(){
|
|
||||||
this.lmilliseconds = (this.frame / 25 * 1000) + this.seconds * 1000 + this.minutes * 60 * 1000 + this.hours * 60 * 60 * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
millisToFrame(millis) {
|
|
||||||
this.frame = Math.floor((millis % 1000)*25/1000);
|
|
||||||
this.seconds = Math.floor((millis / 1000) % 60);
|
|
||||||
this.minutes = Math.floor((millis / (1000*60)) % 60);
|
|
||||||
this.hours = Math.floor((millis / (1000*60*60)) % 24);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ioClient.on("update", (data)=>{
|
|
||||||
activeFile = data.file;
|
|
||||||
var t = data.time;
|
|
||||||
var ft = new FrameTime(t);
|
|
||||||
var answer = {};
|
|
||||||
answer.time = ft;
|
|
||||||
answer.timemillis = t;
|
|
||||||
answer.file = activeFile;
|
|
||||||
answer.playing = data.playing;
|
|
||||||
io.emit("update", answer);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
ioClient.on("playing", (data)=>{
|
|
||||||
io.emit("playing", data);
|
|
||||||
});
|
|
||||||
|
|
||||||
ioClient.on("stopped", ()=>{
|
|
||||||
io.emit("stopped")
|
|
||||||
});
|
|
||||||
|
|
||||||
io.on("connection", (socket)=>{
|
|
||||||
//console.log("client connected:", socket.client.id);
|
|
||||||
socket.on("set", (data)=>{ //ToDo preset ids etc.
|
|
||||||
console.log(data);
|
|
||||||
var entry = {};
|
|
||||||
entry.id = sid.generate();
|
|
||||||
entry.time = new FrameTime(data.time); //typof FrameTime
|
|
||||||
entry.channel = data.channel;
|
|
||||||
entry.note = data.note;
|
|
||||||
entry.name = data.name;
|
|
||||||
data.name = data.name.replace(".", "");
|
|
||||||
entry.value = data.value;
|
|
||||||
if(db.get(data.name).value() === undefined) {
|
|
||||||
db.set(data.name, []).write();
|
|
||||||
}
|
|
||||||
db.get(data.name).push(entry).write();
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("get", (data)=>{ //Requires filename
|
|
||||||
var v = db.get(data.replace(".", "")).value();
|
|
||||||
socket.emit("data", v);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("remove", (data)=>{ //requires id
|
|
||||||
db.get(data.replace(".", "")).remove({id:data}).write();
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("load_preset", (data)=>{
|
|
||||||
toTrigger = db.get(data.replace(".", "")).value();
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("play", (data)=>{
|
|
||||||
ioClient.emit("play", data);
|
|
||||||
});
|
|
||||||
|
|
||||||
socket.on("stop", (data)=>{
|
|
||||||
ioClient.emit("stop", data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
setInterval(()=>{
|
|
||||||
var start
|
|
||||||
var update_infos = {};
|
|
||||||
player.getOrigTime((time)=>{
|
|
||||||
player.getTime((t)=>{
|
|
||||||
player.getState((playing)=>{
|
|
||||||
update_infos.file = activeFile;
|
|
||||||
update_infos.time = t;
|
|
||||||
update_infos.is_playing = playing;
|
|
||||||
update_infos.triggeredMidi = [];
|
|
||||||
if(playing){
|
|
||||||
if(toTrigger){
|
|
||||||
toTrigger.forEach(e=>{
|
|
||||||
if(e.time <= t){
|
|
||||||
var midi = {channel:e.channel, note:e.note, value:e.value}
|
|
||||||
io.emit("midi", {channel:e.channel, note:e.note, value:e.value});
|
|
||||||
var i = toTrigger.indexOf(e);
|
|
||||||
if (i < 0) return;
|
|
||||||
toTrigger.splice(i, 1);
|
|
||||||
update_infos.triggeredMidi.push(midi);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
io.emit("update", update_infos);
|
|
||||||
//console.log(JSON.stringify(update_infos, undefined, 4));
|
|
||||||
})
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}, 1000/25)
|
|
||||||
|
|
||||||
http.listen(5000);
|
|
1
lib/db.json
Normal file
1
lib/db.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{}
|
0
lib/timec.d.ts
vendored
Normal file
0
lib/timec.d.ts
vendored
Normal file
197
lib/timec.js
Normal file
197
lib/timec.js
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
//DATABASE
|
||||||
|
"use strict";
|
||||||
|
const low = require("lowdb");
|
||||||
|
var db = low("db.json");
|
||||||
|
const sid = require("short-id");
|
||||||
|
sid.configure({ length: 12 });
|
||||||
|
db.defaults({}).write();
|
||||||
|
//SOCKETIO
|
||||||
|
const httpp = require("http");
|
||||||
|
var http = httpp.createServer();
|
||||||
|
const io = require("socket.io");
|
||||||
|
var ioClient = require("socket.io-client")("http://localhost:5000");
|
||||||
|
var ios = io(http);
|
||||||
|
const rtpmidi = require("rtpmidi");
|
||||||
|
var midisession = rtpmidi.manager.createSession({
|
||||||
|
localName: "Node Timecode",
|
||||||
|
bonjourName: "Node Timecode",
|
||||||
|
port: 5004
|
||||||
|
});
|
||||||
|
class FrameTime {
|
||||||
|
constructor(millis) {
|
||||||
|
this.lframe = 0;
|
||||||
|
this.lseconds = 0;
|
||||||
|
this.lminutes = 0;
|
||||||
|
this.lhours = 0;
|
||||||
|
this.lmilliseconds = 0;
|
||||||
|
if (Number.isInteger(millis)) {
|
||||||
|
this.milliseconds = millis;
|
||||||
|
}
|
||||||
|
else if (typeof millis === "object") {
|
||||||
|
if (Number.isInteger(millis.frames) && Number.isInteger(millis.seconds) && Number.isInteger(millis.minutes) && Number.isInteger(millis.hours)) {
|
||||||
|
this.lframe = millis.frames; //use the local, because its mor performant
|
||||||
|
this.lseconds = millis.seconds;
|
||||||
|
this.lminutes = millis.minutes;
|
||||||
|
this.lhours = millis.hours;
|
||||||
|
this.calcMillis();
|
||||||
|
}
|
||||||
|
else if (Number.isInteger(millis.milliseconds)) {
|
||||||
|
this.milliseconds = millis.milliseconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get milliseconds() {
|
||||||
|
return this.lmilliseconds;
|
||||||
|
}
|
||||||
|
set milliseconds(val) {
|
||||||
|
this.lmilliseconds = val;
|
||||||
|
this.millisToFrame();
|
||||||
|
}
|
||||||
|
get frame() {
|
||||||
|
return this.lframe;
|
||||||
|
}
|
||||||
|
set frame(val) {
|
||||||
|
this.lframe = val;
|
||||||
|
this.calcMillis();
|
||||||
|
}
|
||||||
|
get seconds() {
|
||||||
|
return this.lseconds;
|
||||||
|
}
|
||||||
|
set seconds(val) {
|
||||||
|
this.lseconds = val;
|
||||||
|
this.calcMillis();
|
||||||
|
}
|
||||||
|
get minutes() {
|
||||||
|
return this.lminutes;
|
||||||
|
}
|
||||||
|
set minutes(val) {
|
||||||
|
this.lminutes = val;
|
||||||
|
this.calcMillis();
|
||||||
|
}
|
||||||
|
get hours() {
|
||||||
|
return this.lhours;
|
||||||
|
}
|
||||||
|
set hours(val) {
|
||||||
|
this.lhours = val;
|
||||||
|
this.calcMillis();
|
||||||
|
}
|
||||||
|
calcMillis() {
|
||||||
|
this.lmilliseconds = (this.frame / 25 * 1000) + this.seconds * 1000 + this.minutes * 60 * 1000 + this.hours * 60 * 60 * 1000;
|
||||||
|
}
|
||||||
|
millisToFrame() {
|
||||||
|
var millis = this.lmilliseconds;
|
||||||
|
this.frame = Math.floor((millis % 1000) * 25 / 1000);
|
||||||
|
this.seconds = Math.floor((millis / 1000) % 60);
|
||||||
|
this.minutes = Math.floor((millis / (1000 * 60)) % 60);
|
||||||
|
this.hours = Math.floor((millis / (1000 * 60 * 60)) % 24);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class Timecode {
|
||||||
|
vlcUpdate(vlc) {
|
||||||
|
this.startTime = new Date().getTime() - vlc.time;
|
||||||
|
this.filePlaying = vlc.file;
|
||||||
|
}
|
||||||
|
update(time) {
|
||||||
|
var d = new Date().getTime() - this.startTime;
|
||||||
|
this.toTrigger.forEach(e => {
|
||||||
|
if (e.time.milliseconds <= d) {
|
||||||
|
ios.emit("midi", e.midi);
|
||||||
|
midisession.sendMessage([e.midi.channel, e.midi.note, e.midi.value]);
|
||||||
|
var i = this.toTrigger.indexOf(e);
|
||||||
|
this.toTrigger.splice(i, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
loadTrack(trackid) {
|
||||||
|
this.playing = false;
|
||||||
|
var track = db.get(trackid).value();
|
||||||
|
track.triggers.forEach(t => {
|
||||||
|
t.time = new FrameTime(t.time);
|
||||||
|
});
|
||||||
|
this.activeTrack = track;
|
||||||
|
this.toTrigger = track.triggers;
|
||||||
|
this.filePlaying = track.file;
|
||||||
|
this.startTime = 0;
|
||||||
|
}
|
||||||
|
play() {
|
||||||
|
if (this.filePlaying) {
|
||||||
|
ioClient.emit("play", { file: this.filePlaying });
|
||||||
|
ioClient.on("playing", () => {
|
||||||
|
this.startTime = new Date().getTime();
|
||||||
|
});
|
||||||
|
ioClient.on("update", (data) => {
|
||||||
|
this.vlcUpdate(data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.startTime = new Date().getTime();
|
||||||
|
this.playing = true;
|
||||||
|
}
|
||||||
|
this.interval = setInterval(this.update.bind(this), 1000 / 25);
|
||||||
|
}
|
||||||
|
stop() {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
this.playing = false;
|
||||||
|
if (this.filePlaying) {
|
||||||
|
ioClient.emit("stop");
|
||||||
|
ios.emit("stopped");
|
||||||
|
}
|
||||||
|
this.startTime = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
class TrackEvent {
|
||||||
|
}
|
||||||
|
class Track {
|
||||||
|
}
|
||||||
|
var timecode = new Timecode();
|
||||||
|
ios.on("connection", socket => {
|
||||||
|
console.log("Client", socket.id, "connected");
|
||||||
|
socket.on("load", (id) => {
|
||||||
|
var track = db.get(id).value();
|
||||||
|
if (track === undefined) {
|
||||||
|
return socket.emit("play_error", "Track doesn't exist");
|
||||||
|
}
|
||||||
|
timecode.loadTrack(id);
|
||||||
|
});
|
||||||
|
socket.on("play", () => {
|
||||||
|
if (timecode.playing) {
|
||||||
|
return socket.emit("play_error", "the active track must be stoppen before re-plaing it");
|
||||||
|
}
|
||||||
|
timecode.play();
|
||||||
|
});
|
||||||
|
socket.on("stop", () => {
|
||||||
|
timecode.stop();
|
||||||
|
timecode.loadTrack(timecode.activeTrack.id);
|
||||||
|
});
|
||||||
|
socket.on("create", (data) => {
|
||||||
|
var track = new Track();
|
||||||
|
track.displayName = data.name;
|
||||||
|
track.file = data.file;
|
||||||
|
track.id = sid.generate();
|
||||||
|
track.triggers = [];
|
||||||
|
db.set(track.id, track).write();
|
||||||
|
socket.emit("created", track);
|
||||||
|
});
|
||||||
|
socket.on("set", (data) => {
|
||||||
|
var tid = data.track;
|
||||||
|
var midi = data.midi;
|
||||||
|
var time = new FrameTime(data.time);
|
||||||
|
var tracke = new TrackEvent();
|
||||||
|
tracke.midi = midi;
|
||||||
|
tracke.time = time;
|
||||||
|
db.get(tid + ".triggers").push(tracke).write();
|
||||||
|
socket.emit("set_finished", tracke);
|
||||||
|
});
|
||||||
|
socket.on("get", () => {
|
||||||
|
socket.emit("get_data", db.getState());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
midisession.on("ready", () => {
|
||||||
|
http.listen(5001);
|
||||||
|
setInterval(() => {
|
||||||
|
midisession.sendMessage([0x80, 0x40]);
|
||||||
|
midisession.sendMessage([0x90, 0x40, 0x7f]);
|
||||||
|
//midisession.sendMessage([1, 5, 100]);
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
|
//# sourceMappingURL=timec.js.map
|
1
lib/timec.js.map
Normal file
1
lib/timec.js.map
Normal file
File diff suppressed because one or more lines are too long
25
package-lock.json
generated
25
package-lock.json
generated
@ -3,6 +3,21 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/node": {
|
||||||
|
"version": "7.0.31",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-7.0.31.tgz",
|
||||||
|
"integrity": "sha512-+KrE1LDddn97ip+gXZAnzNQ0pupKH/6tcKwTpo96BDVNpzmhIKGHug0Wd3H0dN4WEqYB1tXYI5m2mZuIZNI8tg=="
|
||||||
|
},
|
||||||
|
"@types/socket.io": {
|
||||||
|
"version": "1.4.29",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-1.4.29.tgz",
|
||||||
|
"integrity": "sha1-hqazqat4z5qQDO74W5totr6oZxI="
|
||||||
|
},
|
||||||
|
"@types/socket.io-client": {
|
||||||
|
"version": "1.4.29",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.29.tgz",
|
||||||
|
"integrity": "sha1-+HQwcM7pMXXjbgtqd6ivc+WMyzI="
|
||||||
|
},
|
||||||
"accepts": {
|
"accepts": {
|
||||||
"version": "1.3.3",
|
"version": "1.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz",
|
||||||
@ -138,6 +153,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/merge-recursive/-/merge-recursive-0.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/merge-recursive/-/merge-recursive-0.0.3.tgz",
|
||||||
"integrity": "sha1-3nkB78rsyQbYyrKtHpxHD1o9roQ="
|
"integrity": "sha1-3nkB78rsyQbYyrKtHpxHD1o9roQ="
|
||||||
},
|
},
|
||||||
|
"midi-common": {
|
||||||
|
"version": "0.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/midi-common/-/midi-common-0.0.4.tgz",
|
||||||
|
"integrity": "sha1-OC6/3wXh4oMAutER6a1fB6gf7HI="
|
||||||
|
},
|
||||||
"mime-db": {
|
"mime-db": {
|
||||||
"version": "1.27.0",
|
"version": "1.27.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz",
|
||||||
@ -188,6 +208,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
|
||||||
"integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo="
|
"integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo="
|
||||||
},
|
},
|
||||||
|
"rtpmidi": {
|
||||||
|
"version": "0.1.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/rtpmidi/-/rtpmidi-0.1.8.tgz",
|
||||||
|
"integrity": "sha1-deRjzVueLhlzBhXtsKlM8TwuxH4="
|
||||||
|
},
|
||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node test.js",
|
"test": "node test.js",
|
||||||
"start": "node index.js"
|
"start": "node lib/index.js"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -26,7 +26,11 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/margau/node_vlc_rc#readme",
|
"homepage": "https://github.com/margau/node_vlc_rc#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/node": "^7.0.31",
|
||||||
|
"@types/socket.io": "^1.4.29",
|
||||||
|
"@types/socket.io-client": "^1.4.29",
|
||||||
"lowdb": "^0.16.2",
|
"lowdb": "^0.16.2",
|
||||||
|
"rtpmidi": "^0.1.8",
|
||||||
"short-id": "0.1.0-1",
|
"short-id": "0.1.0-1",
|
||||||
"socket.io": "^2.0.3",
|
"socket.io": "^2.0.3",
|
||||||
"socket.io-client": "^2.0.3"
|
"socket.io-client": "^2.0.3"
|
||||||
|
243
src/timec.ts
Normal file
243
src/timec.ts
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
//DATABASE
|
||||||
|
|
||||||
|
import low = require("lowdb");
|
||||||
|
var db = low("db.json");
|
||||||
|
import sid = require("short-id");
|
||||||
|
sid.configure({length:12});
|
||||||
|
db.defaults({}).write();
|
||||||
|
|
||||||
|
//SOCKETIO
|
||||||
|
import * as httpp from "http";
|
||||||
|
var http = httpp.createServer();
|
||||||
|
import io = require("socket.io");
|
||||||
|
var ioClient = require("socket.io-client")("http://localhost:5000");
|
||||||
|
var ios = io(http);
|
||||||
|
|
||||||
|
import rtpmidi = require("rtpmidi");
|
||||||
|
var midisession = rtpmidi.manager.createSession({
|
||||||
|
localName:"Node Timecode",
|
||||||
|
bonjourName:"Node Timecode",
|
||||||
|
port: 5004
|
||||||
|
});
|
||||||
|
|
||||||
|
class FrameTime{
|
||||||
|
lframe = 0;
|
||||||
|
lseconds = 0;
|
||||||
|
lminutes = 0;
|
||||||
|
lhours = 0;
|
||||||
|
lmilliseconds = 0;
|
||||||
|
constructor(millis){
|
||||||
|
if(Number.isInteger(millis)){
|
||||||
|
this.milliseconds = millis;
|
||||||
|
} else if(typeof millis === "object"){
|
||||||
|
if(Number.isInteger(millis.frames) && Number.isInteger(millis.seconds) && Number.isInteger(millis.minutes) && Number.isInteger(millis.hours) ){
|
||||||
|
this.lframe = millis.frames; //use the local, because its mor performant
|
||||||
|
this.lseconds = millis.seconds;
|
||||||
|
this.lminutes = millis.minutes;
|
||||||
|
this.lhours = millis.hours;
|
||||||
|
this.calcMillis();
|
||||||
|
} else if(Number.isInteger(millis.milliseconds)){
|
||||||
|
this.milliseconds = millis.milliseconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get milliseconds() {
|
||||||
|
return this.lmilliseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
set milliseconds(val) {
|
||||||
|
this.lmilliseconds = val;
|
||||||
|
this.millisToFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
get frame(){
|
||||||
|
return this.lframe;
|
||||||
|
}
|
||||||
|
|
||||||
|
set frame (val) {
|
||||||
|
this.lframe = val;
|
||||||
|
this.calcMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
get seconds() {
|
||||||
|
return this.lseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
set seconds(val){
|
||||||
|
this.lseconds = val;
|
||||||
|
this.calcMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
get minutes() {
|
||||||
|
return this.lminutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
set minutes(val) {
|
||||||
|
this.lminutes = val;
|
||||||
|
this.calcMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
get hours(){
|
||||||
|
return this.lhours;
|
||||||
|
}
|
||||||
|
|
||||||
|
set hours(val){
|
||||||
|
this.lhours = val;
|
||||||
|
this.calcMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
calcMillis(){
|
||||||
|
this.lmilliseconds = (this.frame / 25 * 1000) + this.seconds * 1000 + this.minutes * 60 * 1000 + this.hours * 60 * 60 * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
millisToFrame() {
|
||||||
|
var millis = this.lmilliseconds;
|
||||||
|
this.frame = Math.floor((millis % 1000)*25/1000);
|
||||||
|
this.seconds = Math.floor((millis / 1000) % 60);
|
||||||
|
this.minutes = Math.floor((millis / (1000*60)) % 60);
|
||||||
|
this.hours = Math.floor((millis / (1000*60*60)) % 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class Timecode {
|
||||||
|
interval;
|
||||||
|
playing:boolean;
|
||||||
|
activeTrack:Track;
|
||||||
|
filePlaying:string;
|
||||||
|
startTime:number;
|
||||||
|
toTrigger:Array<TrackEvent>;
|
||||||
|
|
||||||
|
vlcUpdate(vlc:VlcUpdate) {
|
||||||
|
this.startTime = new Date().getTime() - vlc.time;
|
||||||
|
this.filePlaying = vlc.file;
|
||||||
|
}
|
||||||
|
|
||||||
|
update(time:FrameTime) {
|
||||||
|
var d = new Date().getTime() - this.startTime;
|
||||||
|
this.toTrigger.forEach(e=>{
|
||||||
|
if(e.time.milliseconds <= d) {
|
||||||
|
ios.emit("midi", e.midi);
|
||||||
|
midisession.sendMessage([e.midi.channel, e.midi.note, e.midi.value]);
|
||||||
|
var i = this.toTrigger.indexOf(e);
|
||||||
|
this.toTrigger.splice(i, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
loadTrack(trackid:string) {
|
||||||
|
this.playing = false;
|
||||||
|
var track =<Track>db.get(trackid).value();
|
||||||
|
track.triggers.forEach(t=>{
|
||||||
|
t.time = new FrameTime(t.time);
|
||||||
|
});
|
||||||
|
this.activeTrack = track;
|
||||||
|
this.toTrigger = track.triggers;
|
||||||
|
this.filePlaying = track.file;
|
||||||
|
this.startTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
play() {
|
||||||
|
if(this.filePlaying){
|
||||||
|
ioClient.emit("play", {file:this.filePlaying});
|
||||||
|
ioClient.on("playing", ()=>{
|
||||||
|
this.startTime = new Date().getTime();
|
||||||
|
});
|
||||||
|
ioClient.on("update", (data)=>{
|
||||||
|
this.vlcUpdate(data);
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this.startTime = new Date().getTime();
|
||||||
|
this.playing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.interval = setInterval(this.update.bind(this), 1000/25);
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
clearInterval(this.interval);
|
||||||
|
this.playing = false;
|
||||||
|
if(this.filePlaying){
|
||||||
|
ioClient.emit("stop");
|
||||||
|
ios.emit("stopped");
|
||||||
|
}
|
||||||
|
this.startTime = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TrackEvent {
|
||||||
|
midi: {
|
||||||
|
channel:number,
|
||||||
|
note:number,
|
||||||
|
value:number
|
||||||
|
}
|
||||||
|
time:FrameTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Track {
|
||||||
|
id:string
|
||||||
|
displayName:string;
|
||||||
|
triggers:Array<TrackEvent>;
|
||||||
|
file:string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VlcUpdate {
|
||||||
|
file:string,
|
||||||
|
time:number,
|
||||||
|
is_playing:boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
var timecode = new Timecode();
|
||||||
|
ios.on("connection", socket=>{
|
||||||
|
console.log("Client", socket.id, "connected");
|
||||||
|
socket.on("load", (id)=>{
|
||||||
|
var track = db.get(id).value();
|
||||||
|
if(track === undefined){
|
||||||
|
return socket.emit("play_error", "Track doesn't exist");
|
||||||
|
}
|
||||||
|
timecode.loadTrack(id);
|
||||||
|
});
|
||||||
|
socket.on("play", ()=>{
|
||||||
|
if(timecode.playing){
|
||||||
|
return socket.emit("play_error", "the active track must be stoppen before re-plaing it");
|
||||||
|
}
|
||||||
|
timecode.play();
|
||||||
|
});
|
||||||
|
socket.on("stop", ()=>{
|
||||||
|
timecode.stop();
|
||||||
|
timecode.loadTrack(timecode.activeTrack.id);
|
||||||
|
});
|
||||||
|
socket.on("create", (data)=>{
|
||||||
|
var track = new Track();
|
||||||
|
track.displayName = data.name;
|
||||||
|
track.file = data.file;
|
||||||
|
track.id = sid.generate();
|
||||||
|
track.triggers = [];
|
||||||
|
db.set(track.id, track).write();
|
||||||
|
socket.emit("created", track);
|
||||||
|
});
|
||||||
|
socket.on("set", (data)=>{
|
||||||
|
var tid = data.track;
|
||||||
|
var midi = data.midi;
|
||||||
|
var time = new FrameTime(data.time);
|
||||||
|
var tracke = new TrackEvent();
|
||||||
|
tracke.midi = midi;
|
||||||
|
tracke.time = time;
|
||||||
|
db.get(tid + ".triggers").push(tracke).write();
|
||||||
|
socket.emit("set_finished", tracke);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("get", ()=>{
|
||||||
|
socket.emit("get_data", db.getState());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
midisession.on("ready", ()=>{
|
||||||
|
http.listen(5001);
|
||||||
|
setInterval(()=>{
|
||||||
|
midisession.sendMessage([0x80, 0x40]);
|
||||||
|
midisession.sendMessage([0x90, 0x40, 0x7f]);
|
||||||
|
//midisession.sendMessage([1, 5, 100]);
|
||||||
|
}, 500);
|
||||||
|
});
|
13
testEvent.json
Normal file
13
testEvent.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"track": "3d47edcdc882",
|
||||||
|
"midi":{
|
||||||
|
"channel":1,
|
||||||
|
"note":3,
|
||||||
|
"value":4
|
||||||
|
}, "time": {
|
||||||
|
"hours":0,
|
||||||
|
"minutes": 0,
|
||||||
|
"seconds":5,
|
||||||
|
"frames": 15
|
||||||
|
}
|
||||||
|
}
|
21
tsconfig.json
Normal file
21
tsconfig.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"target": "es6",
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"sourceMap": true,
|
||||||
|
"outDir": "lib",
|
||||||
|
"declaration": true,
|
||||||
|
"typeRoots": [
|
||||||
|
"node_modules/@types"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"src/custom.d.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
],"include": [
|
||||||
|
"src"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user