/**
* scripts/doubleroll.js
*
* This is the starting point for your application.
* Take a look at http://browserify.org/ for more info
*/
/* global window: false */
/* global document: false */
/* global WebSocket: false */
/* global MozWebSocket: false */
'use strict';
var PIXI = require('pixi');
var _ = require('lodash');
var PianoRoll = require('./pianoroll.js');
var NTP_EPOCH_DELTA = 2208988800; //c.f. RFC 868
var defaultConfig = {
orientation: 'horizontal',
logger: false,
sceneWidth: 1920,
pianorolls : [
{
height: 435,
timeWidth: 10,
lineInterval: 5000,
noteHeight: undefined
},
{
height: 645,
timeWidth: 60,
lineInterval: 5000,
noteHeight: undefined
},
],
framerate: 25,
offsetMusic: false,
sceneBgColor: 0xFFFFFF,
lineColor: 0x444444,
lineFillColor: 0xFFFF00,
noteColors: [0xB90000, 0x4BDD71, 0xAF931E, 0x1C28BA, 0x536991],
canvasContainer: 'canvasContainer',
logContainer: 'log',
timeContainer: 'timeStarted',
noteHeight: undefined,
zeroShift: 0.9,
timeWidth: 60,
lineInterval: 5000,
annotationChannel: 'PIANOROLL'
// wsUri: undefined,
// eventCode: undefined
};
function DoubleRoll(options) {
var _this = this;
var opts = _(options).defaults(defaultConfig).value();
var orientation = opts.orientation;
var isHorizontal = (orientation !== 'vertical');
this.logger = opts.logger;
this.lineColor = opts.lineColor;
this.lineFillColor = opts.lineFillColor;
this.framerate = opts.framerate;
this.offsetMusic = opts.offsetMusic;
this.noteColors = opts.noteColors;
var noteHeight = opts.noteHeight;
var sceneBgColor = opts.sceneBgColor;
var sceneHeight = opts.sceneHeight || _(opts.pianorolls).reduce(function(s,p) { return s + p.height; }, 0);
var timeWidth = opts.timeWidth;
var lineInterval = opts.lineInterval;
var offsetMusic = opts.offsetMusic;
var sceneWidth = opts.sceneWidth;
var canvasContainer = opts.canvasContainer;
var logContainer = opts.logContainer;
var timeContainer = opts.timeContainer;
var zeroShift = opts.zeroShift;
var eventCode = opts.eventCode;
var annotationChannel = opts.annotationChannel;
var wsUri = opts.wsUri;
if(!wsUri) {
if (window.location.protocol === 'file:') {
wsUri = 'ws://127.0.0.1:8090/broadcast';
}
else {
wsUri = 'ws://' + window.location.hostname + ':8090/broadcast';
}
wsUri += '?channel='+annotationChannel+'&event_code='+eventCode;
}
var colorsReg = {};
//create an new instance of a pixi stage
var stage = new PIXI.Stage(sceneBgColor);
//create a renderer instance.
var renderer = PIXI.autoDetectRenderer(sceneWidth, sceneHeight);
var uberContainer = new PIXI.DisplayObjectContainer();
uberContainer.x = Math.floor(sceneWidth*zeroShift);
uberContainer.y = 0;
stage.addChild(uberContainer);
var pianorollList = [];
var pianorollOptions = {
parentContainer: uberContainer,
orientation: orientation,
xInit: 0,
width: sceneWidth,
noteColors: this.noteColors,
colorsReg: colorsReg,
lineColor: this.lineColor,
lineInterval: lineInterval,
offsetMusic: offsetMusic,
};
var yInit = 0;
var linesDown = true;
_(opts.pianorolls).forEach(function(prDef, i) {
var prNoteHeight = noteHeight || prDef.noteHeight || prDef.height / 128;
var prTimeWidth = prDef.timeWidth || timeWidth;
pianorollList.push(new PianoRoll(_({
yInit: yInit,
height: prDef.height,
linesDown: linesDown,
pixelsPerSecond: Math.floor(sceneWidth / prTimeWidth),
noteHeight: prNoteHeight,
lineInterval: prDef.lineInterval
}).defaults(pianorollOptions).value()));
yInit += prDef.height;
linesDown = !linesDown;
if(i<(opts.pianorolls.length-1)) {
var lineGraphics = new PIXI.Graphics()
.beginFill(_this.lineFillColor)
.lineStyle(1, _this.lineColor)
.moveTo(Math.floor(sceneWidth*zeroShift), yInit)
.lineTo(-sceneWidth - Math.floor(sceneWidth*zeroShift), yInit)
.endFill();
uberContainer.addChild(lineGraphics);
}
});
if(!isHorizontal) {
uberContainer.rotation = Math.PI/2;
uberContainer.y = sceneHeight;
uberContainer.x = sceneWidth;
}
this.init = function() {
if(typeof(canvasContainer) === 'string') {
canvasContainer = document.getElementById(canvasContainer);
}
if(typeof(logContainer) === 'string') {
logContainer = document.getElementById(logContainer);
}
if(typeof(timeContainer) === 'string') {
timeContainer = document.getElementById(timeContainer);
}
if(!this.logger){
document.body.removeChild(logContainer);
logContainer = undefined;
}
var sock;
canvasContainer.appendChild(renderer.view);
if ('WebSocket' in window) {
sock = new WebSocket(wsUri);
} else if ('MozWebSocket' in window) {
sock = new MozWebSocket(wsUri);
} else {
this.log('Browser does not support WebSocket!');
window.location = 'http://autobahn.ws/unsupportedbrowser';
}
if (!sock) {
return;
}
sock.onopen = function(){
if(_this.logger){
_this.log('Connected to ' + _this.wsUri);
}
};
sock.onclose = function(e) {
if(_this.logger){
_this.log('Connection closed (wasClean = ' + e.wasClean + ', code = ' + e.code + ', reason = \'' + e.reason + '\')');
}
sock = null;
};
sock.onmessage = function(e) {
var dataJson = JSON.parse(e.data);
if(_this.logger){
var dataDate = new Date((dataJson.content[0]-NTP_EPOCH_DELTA)*1000);
_this.log('Got message: ' + e.data + ' - ' + dataDate.toISOString());
}
_this.addNotes(dataJson);
};
};
this.addNotes = function(data) {
var note = data.content[3];
var velocity = data.content[4];
var ts = (data.content[0] - NTP_EPOCH_DELTA)*1000;
var channel = data.content[2];
var sessionTs = data.content[1];
pianorollList.forEach(function(c) {
c.addNote(note, ts, sessionTs, velocity, channel, 0);
});
};
this.refreshStage = function() {
pianorollList.forEach(function(c) {
c.move();
});
renderer.render(stage);
};
// Init page and intervals
var refreshInterval;
var refreshTimeInterval;
var startTs;
this.updateTime = function(){
var nbSec = (Date.now() - startTs) / 1000;
var hours = Math.floor( nbSec / 3600 ) % 24;
var minutes = Math.floor( nbSec / 60 ) % 60;
var seconds = Math.floor(nbSec % 60);
var timeStr = (hours < 10 ? '0' + hours : hours) + ':' + (minutes < 10 ? '0' + minutes : minutes) + ':' + (seconds < 10 ? '0' + seconds : seconds);
timeContainer.innerHTML = timeStr;
};
this.start = function() {
startTs = Date.now();
refreshInterval = window.setInterval(function() {_this.refreshStage();}, 1000/this.framerate);
refreshTimeInterval = window.setInterval(function() {_this.updateTime();}, 1000);
pianorollList.forEach(function(c) {
c.start();
});
};
this.stop = function() {
window.clearInterval(refreshInterval);
window.clearInterval(refreshTimeInterval);
pianorollList.forEach(function(c) {
c.stop();
});
};
this.log = function(m) {
if(this.logger){
this.logContainer.innerHTML += m + '\n';
this.logContainer.scrollTop = logContainer.scrollHeight;
}
};
window.onload = function() {
_this.init();
_this.start();
};
return this;
}
module.exports = {
DoubleRoll: DoubleRoll
};