This commit is contained in:
Fabian Stamm
2017-06-18 13:45:29 +02:00
parent 53a6052375
commit 8683ea17a3
14 changed files with 555 additions and 188 deletions

243
src/timec.ts Normal file
View 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);
});