Merge with 72d767c5142df7fc6387215096321295fbaaa73d
Update doubleroll and annotsroll to support stageView
--- a/annot-server/websockets.py Tue Jan 20 12:00:40 2015 +0100
+++ b/annot-server/websockets.py Tue Jan 20 18:37:51 2015 +0100
@@ -1,4 +1,3 @@
-
#
# See LICENCE for detail
# Copyright (c) 2014 IRI
@@ -50,8 +49,8 @@
def register(self, client):
if not client in self.clients:
- print("registered client {}".format(client.peer))
- self.clients.append(client)
+ print("registered client {}".format(client.peer))
+ self.clients.append(client)
def unregister(self, client):
if client in self.clients:
@@ -60,11 +59,11 @@
if client in self.filters:
self.filters.pop(client, None)
- def broadcast(self, msg, filter):
+ def broadcast(self, msg, filter_list):
print("broadcasting prepared message '{}' ..".format(msg))
preparedMsg = self.prepareMessage(msg)
for c in self.clients:
- if all([ (k in filter and filter[k] in v) for k,v in self.filters.get(c, {}).items()]):
+ if all([ (k in filter_list and filter_list[k] in v) for k,v in self.filters.get(c, {}).items()]):
c.sendPreparedMessage(preparedMsg)
print("prepared message sent to {}".format(c.peer))
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annotviz/app/annotsroll.html Tue Jan 20 18:37:51 2015 +0100
@@ -0,0 +1,92 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width,initial-scale=1">
+ <meta name="description" content="">
+ <meta name="author" content="I.R.I">
+ <link rel="shortcut icon" href="/img/favicon.ico">
+
+ <title>AnnotsRoll</title>
+
+ <!-- Custom styles for this template -->
+ <link href="/css/annotviz.css" rel="stylesheet">
+</head>
+
+<body>
+ <h1>Piano Roll vertical</h1>
+ <noscript>You must enable JavaScript</noscript>
+ <div id="canvasContainer"></div>
+ <p>
+ <a href="#" onclick="stop(); return false;">stop intervals</a> -
+ <a href="#" onclick="start(); return false;">start intervals</a> -
+ temps écoulé : <span id="timeStarted"></span>
+ </p>
+ <!--pre id="log"></pre-->
+ <script src="/js/libs-annotviz.js"></script>
+ <script src="/js/annotviz.js"></script>
+ <script>
+ var pianorollChannel = 'PIANOROLL';
+ var annotationChannel = 'ANNOT';
+ var eventCode = 'test_1';
+ var wsUri;
+ if (window.location.protocol === 'file:') {
+ wsUri = 'ws://127.0.0.1:8090/broadcast';
+ }
+ else {
+ wsUri = 'ws://' + window.location.hostname + ':8090/broadcast';
+ }
+ wsUriPianoroll = wsUri + '?channel=' + pianorollChannel + '&event_code=' + eventCode;
+ wsUriAnnotation = wsUri + '?channel=' + annotationChannel + '&event_code=' + eventCode;
+
+ var logger = new annotviz.ConsoleLogger(true);
+
+ var stageView = new annotviz.StageView({
+ logger: logger
+ });
+
+ var doubleroll = new annotviz.DoubleRoll({
+ stageView : stageView,
+ logger: logger,
+ ws: new annotviz.WsWrapper(wsUriPianoroll, logger),
+ orientation: 'vertical',
+ sceneHeight: 1080,
+ pianorolls : [
+ {
+ height: 435,
+ timeWidth: 60,
+ lineInterval: 5000,
+ noteHeight: undefined
+ },
+ ]
+ });
+
+ var annotsroll = new annotviz.AnnotsRoll({
+ stageView : stageView,
+ logger: logger,
+ ws: new annotviz.WsWrapper(wsUriAnnotation, logger),
+ parentContainer: doubleroll.stage,
+ xInit: 1920 - 435 - 300,
+ yInit: 1080,
+ width: 1920,
+ height: 1080,
+ widthRoll: 300,
+ framerate: doubleroll.framerate,
+ pixelsPerSecond: Math.floor(1920 / 60),
+ annotColors: [{ts: 0, colors: {'ntm' : '#cdc83f'}}],
+ });
+
+ function stop() {
+ stageView.stop();
+ }
+ function start() {
+ stageView.start();
+ }
+
+ window.onload = function() {
+ stageView.init();
+ start();
+ }
+ </script>
+</body>
+</html>
--- a/client/annotviz/app/index.html Tue Jan 20 12:00:40 2015 +0100
+++ b/client/annotviz/app/index.html Tue Jan 20 18:37:51 2015 +0100
@@ -7,29 +7,21 @@
<meta name="author" content="I.R.I">
<link rel="shortcut icon" href="/img/favicon.ico">
- <title>Piano Roll</title>
+ <title>Piano Roll Tests</title>
<!-- Custom styles for this template -->
<link href="/css/annotviz.css" rel="stylesheet">
</head>
<body>
- <h1>Piano Roll</h1>
- <noscript>You must enable JavaScript</noscript>
- <div id="canvasContainer"></div>
+ <h1>Piano Roll Tests</h1>
<p>
- <a href="#" onclick="clearInterval(moveInterval); clearInterval(verticalLinesInterval); return false;">stop intervals</a>
- - temps écoulé : <span id="myspan"></span>
+ <ul>
+ <li><a href="pianoroll_h.html">Horizontal Pianoroll</a></li>
+ <li><a href="pianoroll_v.html">Vertical Pianoroll</a></li>
+ <li><a href="annotsroll.html">AnnotsRoll</a></li>
+ <li><a href="annotstimeline.html">AnnotsTimeLine</a></li>
+ </ul>
</p>
- <pre id="log"></pre>
- <script src="/js/libs-annotviz.js"></script>
- <script>
- var eventCode = "test_1";
- </script>
- <script src="/js/annotviz.js"></script>
- <script>
- var moveInterval = annotviz.moveInterval;
- var verticalLinesInterval = annotviz.verticalLinesInterval;
- </script>
</body>
</html>
--- a/client/annotviz/app/js/annotsRoll.js Tue Jan 20 12:00:40 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/**
-* js/annotsRoll.js
-*
-* annotsRoll basic component
-*
-*/
-
-'use strict';
-
-var PIXI = require('pixi');
-var randomColor = require('randomColor');
-
-function AnnotsRoll(parentContainer, xInit, yInit, width, height, widthRoll, pixelsPerSecond, annotColors, lineInterval){
- var _this = this;
- this.container = new PIXI.DisplayObjectContainer();
- this.container.position.x = xInit;
- this.container.position.y = yInit;
- this.container.width = width;
- parentContainer.addChild(this.container);
-
- this.height = height;
- this.width = width;
- this.widthRoll = widthRoll;
- this.pixelsPerSecond = pixelsPerSecond;
- this.lineInterval = lineInterval;
-
- this.addAnnot = function(category, user, color){
- var graphics = new PIXI.Graphics();
- var x = 0;
- var y = -this.container.y;
- graphics.beginFill(color);
- graphics.drawRect(x, y, 10, 3);
- graphics.endFill();
-
- this.container.addChild(graphics);
-
- var catText = new PIXI.Text(category, { font: '16pt Arial', fill: color.replace("0x", "#") });
- catText.x = x + 20;
- catText.y = y - 23;
- this.container.addChild(catText);
-
- var userText = new PIXI.Text(user, { font: '10pt Arial', fill: '#444444' });
- userText.x = x + 20;
- userText.y = y + 2;
- this.container.addChild(userText);
-
- this.addAnnotLine(color);
- };
-
- this.addAnnotLine = function(color){
- var x = this.widthRoll;
- var y = -this.container.y;
-
- var graphics = new PIXI.Graphics();
-
- graphics.beginFill(color);
- graphics.drawRect(x, y, this.width - x, 3);
- graphics.endFill();
-
- this.container.addChild(graphics);
- };
-
- this.moveTo = function(diffTime){
- this.container.y = Math.floor(diffTime*this.pixelsPerSecond);
- };
-
- this.removePassedObjets = function(){
- var nbChilds = _this.container.children.length;
- var i = 0, childIsNowDisplayed = false, childrenToRemove = [];
- while(i<nbChilds && !childIsNowDisplayed){
- var child = _this.container.children[i++];
-
- if(typeof(child) == 'undefined') {
- continue;
- }
- if((child.y + child.height) < (Math.abs(_this.container.y) - _this.height)){
- childrenToRemove.push(child);
- }
- else {
- childIsNowDisplayed = true;
- }
- }
- childrenToRemove.forEach(function(child) {
- _this.container.removeChild(child);
- });
- };
-
- window.setInterval(this.removePassedObjets, 1000 * this.height / this.pixelsPerSecond );
-
-}
-
-module.exports = AnnotsRoll;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annotviz/app/js/annotsroll.js Tue Jan 20 18:37:51 2015 +0100
@@ -0,0 +1,221 @@
+/**
+* js/annotsRoll.js
+*
+* annotsRoll basic component
+*
+*/
+
+'use strict';
+
+var PIXI = require('pixi');
+var _ = require('lodash');
+
+//
+//
+//
+// options = {
+// parentContainer:,
+// externalRefresh: true/false
+// ws:,
+// xInit:,
+// yInit:,
+// width:,
+// height:,
+// widthRoll:,
+// pixelsPerSecond:,
+// framerate:,
+// annotColors: [{ts: , colors: {code1 : '#dshdsj', code2: 'sdasd', 'default': 'dsadas'}}],
+// defaultColor: default,
+// annotStyles: {
+// 'label': {font:, fill:},
+// 'text':{font:, fill:},
+// 'user':{font:, fill:},
+// }
+// }
+var DEFAULT_ANNOT_COLOR = '#bababa';
+
+var defaultAnnotStyles = {
+ 'label': { font: '26pt Arial Bold', fill: '#65A954' },
+ 'text' : { font: '20pt Arial Regular', fill: '#444444' },
+ 'user' : { font: '22pt Arial regular', fill: '#444444' },
+};
+
+var defaultOptions = {
+ externalRefresh: false,
+ defaultColor: DEFAULT_ANNOT_COLOR,
+ annotStyles: defaultAnnotStyles
+};
+
+function AnnotsRoll(options) {
+
+//parentContainer, xInit, yInit, width, height, widthRoll, pixelsPerSecond, annotColors
+ var _this = this;
+ var opts = _(options).defaults(defaultOptions).value();
+
+
+ this.container = new PIXI.DisplayObjectContainer();
+ this.container.x = opts.xInit;
+ this.container.y = opts.yInit;
+ this.container.width = opts.width;
+
+ this.height = opts.height;
+ this.width = opts.width;
+ this.widthRoll = opts.widthRoll;
+ this.pixelsPerSecond = opts.pixelsPerSecond;
+ this.annotColors = opts.annotColors;
+ this.startTs = options.startTs || Date.now();
+
+ var yInit = opts.yInit;
+ var annotStyles = _(opts.annotStyles).defaults(defaultAnnotStyles).value();
+ var started = false;
+ var ws = opts.ws;
+ var externalRefresh = opts.externalRefresh;
+ var stageView = opts.stageView;
+
+ stageView.registerComponent(this);
+
+ var isHidden = function(child) {
+ // TODO: the origin point is an approximation. Should refine this
+ var globalPos = child.toGlobal(new PIXI.Point(0,0));
+ return ((globalPos.x + child.width) < 0) || ((globalPos.y + child.height) < 0) ;
+ };
+
+ this.addAnnots = function(data) {
+
+ //var title = data.content.category.label;
+ //var user = data.content.user;
+ //Test cat and color
+ //var colorAnnot = 0x65A954;
+ var category = data.content.category.label,
+ text = data.content.text,
+ user = data.content.user,
+ ts = Date.parse(data.ts),
+ color = this.getColor(ts, data.content.category.code);
+
+ this.addAnnot(category, text, user, color, ts);
+ };
+
+ this.getColor = function(ts, code) {
+ var colorsDef;
+ _(this.annotColors).eachRight(function(cdef) {
+ console.log("cDef", cdef);
+ console.log("cDef ts", cdef.ts, ts);
+ if(cdef.ts < ts) {
+ colorsDef = cdef.colors;
+ return false;
+ }
+ });
+ var resColor;
+ console.log("colorsDef", colorsDef);
+ if(colorsDef) {
+ resColor = colorsDef[code];
+ }
+ if(!resColor) {
+ resColor = DEFAULT_ANNOT_COLOR;
+ }
+ return resColor;
+ }
+
+ this.addAnnot = function(category, text, user, catColor, ts){
+
+ var color = catColor ? catColor : DEFAULT_ANNOT_COLOR;
+ var x = 0;
+ var y = (ts-this.startTs) * this.pixelsPerSecond / 1000 + yInit;
+
+ var colorHex = parseInt(color.replace(/^#/, ''), 16);
+
+ var graphics = new PIXI.Graphics()
+ .beginFill(colorHex)
+ .drawRect(x, y, 10, 3)
+ .endFill();
+
+ this.container.addChild(graphics);
+
+ var catLabel = new PIXI.Text(
+ category,
+ _(annotStyles.label).extend({fill: color}).value()
+ );
+ catLabel.x = x + 20;
+ catLabel.y = y - 23;
+ this.container.addChild(catLabel);
+
+ var textHeight = 0;
+ if(text) {
+ var catText = new PIXI.Text(text, annotStyles.text);
+ catText.x = x + 20;
+ catText.y = y + 2;
+ this.container.addChild(catText);
+ textHeight += (catText.height + 2);
+ }
+
+ var catUser = new PIXI.Text(user, annotStyles.user);
+ catUser.x = x + 20;
+ catUser.y = y + 2 + textHeight;
+ this.container.addChild(catUser);
+
+ this.addAnnotLine(colorHex, y);
+ };
+
+ this.addAnnotLine = function(color, y) {
+ var x = this.widthRoll;
+
+
+ var graphics = new PIXI.Graphics()
+ .beginFill(color)
+ .drawRect(x, y, this.width - x, 3)
+ .endFill();
+
+ this.container.addChild(graphics);
+ };
+
+ this.moveTo = function(diffTime){
+ this.container.y = Math.floor(diffTime*this.pixelsPerSecond);
+ };
+
+ this.move = this.refresh = function() {
+ var diff = (this.startTs - Date.now())/1000;
+ this.moveTo(diff);
+ };
+
+ this.removePassedObjets = function(){
+ var childrenToRemove = [];
+ _(_this.container.children).forEach(function(child) {
+ return typeof(child) === 'undefined' ||
+ (isHidden(child) && childrenToRemove.push(child));
+ });
+ childrenToRemove.forEach(function(child) {
+ _this.container.removeChild(child);
+ });
+ };
+
+ this.init = function() {
+
+ ws.message(function(data) {
+ _this.addAnnots(data);
+ });
+
+ };
+
+ this.start = function() {
+ if(!started) {
+ this.startTs = Date.now();
+ started = true;
+ }
+ this.cleanInterval = setInterval(function () { _this.removePassedObjets(); }, 1000 * this.height / this.pixelsPerSecond );
+ if(!externalRefresh) {
+ this.refreshInterval = setInterval(function() {_this.move();}, 1000/this.framerate);
+ }
+ };
+
+ this.stop = function() {
+ clearInterval(this.cleanInterval);
+ if(!externalRefresh) {
+ clearInterval(this.refreshInterval);
+ }
+ };
+
+}
+
+module.exports = {
+ AnnotsRoll: AnnotsRoll,
+};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annotviz/app/js/annotstimeline.js Tue Jan 20 18:37:51 2015 +0100
@@ -0,0 +1,134 @@
+/**
+* js/annotstimeline
+*
+* annotstimeline basic component
+*
+*/
+
+'use strict';
+
+var PIXI = require('pixi');
+var _ = require('lodash');
+var rgb2hex = require('./utils');
+
+var defaultOptions = {
+ logger: undefined,
+ intervalWidth: 10,
+ intervalHeight: 5,
+ maxCellHeight: 20,
+};
+
+
+function AnnotsTimeLine(options){
+ var _this = this;
+ var opts = _(options).defaults(defaultOptions).value();
+
+ this.container = new PIXI.DisplayObjectContainer();
+ this.container.x = opts.xInit;
+ this.container.y = opts.yInit;
+ this.container.width = opts.width;
+ this.container.height = opts.height;
+
+ this.timeBegin = opts.timeBegin;
+ this.timeEnd = opts.timeEnd;
+ this.duration = (this.timeEnd - this.timeBegin)/1000;
+ this.width = opts.width;
+ this.height = opts.height;
+ this.intervalHeight = opts.intervalHeight;
+ this.intervalWidth = opts.intervalWidth;
+ this.maxCellHeight = opts.maxCellHeight;
+ this.intervalDuration = (this.intervalWidth * this.duration / this.width);
+ this.annotCategories = opts.annotCategories;
+
+ this.cells = []
+ for (var i=0; i<(this.width/this.intervalWidth) ; i++){
+ this.cells[i] = [];
+ this.cells[i].x = i * this.intervalWidth;
+ this.cells[i].totalAnnots = 0;
+ this.cells[i].graphics = new PIXI.Graphics();
+ this.container.addChild(this.cells[i].graphics);
+ this.cells[i].categories = {};
+
+ for (var category in this.annotCategories[0].colors){
+ this.cells[i].categories[category] = {
+ "count": 0,
+ "color": this.annotCategories[0].colors[category]
+ };
+ }
+ }
+
+ var ws = opts.ws;
+ var stageView = opts.stageView;
+ // draw temp line to locate the middle of the container
+ var graphics = new PIXI.Graphics();
+ graphics.beginFill(0x000000)
+ .lineStyle(1, 0x000000)
+ .moveTo(this.container.x, (this.height/2))
+ .lineTo(this.width, (this.height/2))
+ .endFill();
+ this.container.addChild(graphics);
+
+ stageView.registerComponent(this);
+
+ //Add Annotation to the TimeLine
+ this.addAnnot = function(data){
+ if (typeof(this.annotCategories[0].colors[data.content.category.code]) !== 'undefined'){
+ var annotCode = data.content.category.code;
+ } else {
+ var annotCode = this.annotCategories[0].order[this.annotCategories[0].order.length -1];
+ }
+ var annotTime = Date.parse(data.ts);
+
+ if (this.timeEnd > Date.parse(data.ts)){
+ var i = Math.floor((Date.parse(data.ts)-this.timeBegin)/(1000*this.intervalDuration));
+ this.cells[i].categories[annotCode].count += 1;
+ this.cells[i].totalAnnots +=1;
+ this.redrawCell(this.cells[i]);
+ }
+ };
+
+ //Draw the cellule
+ this.redrawCell = function(cell){
+ var x = cell.x;
+ var y = this.height/2;
+ cell.graphics.clear();
+
+ //Check if total height is higher than Max Cell Height
+ if ((cell.totalAnnots*this.intervalHeight) > this.maxCellHeight){
+ var heightStep = this.maxCellHeight/cell.totalAnnots;
+ } else {
+ var heightStep = this.intervalHeight;
+ }
+ //Draw the rect depending on the height step calculated
+ for (var i=0; i< this.annotCategories[0].order.length; i++){
+ var currentCode = this.annotCategories[0].order[i];
+ cell.graphics.beginFill(cell.categories[currentCode].color.replace("#", "0x"))
+ .drawRect(x, y, this.intervalWidth, -cell.categories[currentCode].count * heightStep)
+ .endFill();
+ y -= cell.categories[currentCode].count*heightStep;
+ }
+ }
+
+ this.init = function() {
+
+ ws.message(function(data) {
+ _this.addAnnot(data);
+ });
+
+ };
+
+ this.start = function() {
+ };
+
+ this.refresh = function() {
+ };
+
+ this.stop = function(){
+ };
+
+ return this;
+}
+
+module.exports = {
+ AnnotsTimeLine: AnnotsTimeLine
+};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annotviz/app/js/annotsvizview.js Tue Jan 20 18:37:51 2015 +0100
@@ -0,0 +1,6 @@
+/**
+* js/annotsvizview.js
+*
+* This is the starting point for your application.
+* Take a look at http://browserify.org/ for more info
+*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annotviz/app/js/doubleroll.js Tue Jan 20 18:37:51 2015 +0100
@@ -0,0 +1,189 @@
+/**
+* scripts/doubleroll.js
+*
+* This is the starting point for your application.
+* Take a look at http://browserify.org/ for more info
+*/
+
+/* global document: false */
+
+'use strict';
+
+
+var PIXI = require('pixi');
+var _ = require('lodash');
+var PianoRoll = require('./pianoroll.js');
+
+var defaultConfig = {
+ orientation: 'horizontal',
+ logger: undefined,
+ 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],
+ noteHeight: undefined,
+ zeroShift: 0.9,
+ timeWidth: 60,
+ lineInterval: 5000,
+// 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 stageView = opts.stageView;
+
+ var zeroShift = opts.zeroShift;
+
+ var ws = opts.ws;
+
+ var colorsReg = {};
+
+ this.container = new PIXI.DisplayObjectContainer();
+ this.container.x = Math.floor(sceneWidth*zeroShift);
+ this.container.y = 0;
+
+ stageView.registerComponent(this);
+
+ var pianorollList = [];
+
+ var pianorollOptions = {
+ parentContainer: this.container,
+ 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();
+ _this.container.addChild(lineGraphics);
+ }
+ });
+
+ if(!isHorizontal) {
+ this.container.rotation = Math.PI/2;
+ this.container.y = sceneHeight;
+ this.container.x = sceneWidth;
+ }
+
+
+ this.init = function() {
+
+ ws.message(function(data) {
+ _this.addNotes(data);
+ });
+
+ };
+
+
+ this.addNotes = function(data) {
+
+ pianorollList.forEach(function(c) {
+ c.addNoteRaw(data);
+ });
+ };
+
+ this.refresh = function() {
+ pianorollList.forEach(function(c) {
+ c.move();
+ });
+ };
+
+ // Init page and intervals
+ var startTs;
+
+ this.start = function() {
+
+ startTs = Date.now();
+ pianorollList.forEach(function(c) {
+ c.start();
+ });
+ };
+
+ this.stop = function() {
+
+ pianorollList.forEach(function(c) {
+ c.stop();
+ });
+ };
+
+
+ this.log = function(m) {
+ if(this.logger) {
+ this.logger.log(m);
+ }
+ };
+
+
+
+ return this;
+}
+
+module.exports = {
+ DoubleRoll: DoubleRoll
+};
--- a/client/annotviz/app/js/generalView.js Tue Jan 20 12:00:40 2015 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-/**
-* js/generalView
-*
-* generalView basic component
-*
-*/
-
-'use strict';
-
-var PIXI = require('pixi');
-var randomColor = require('randomColor');
-var rgb2hex = require('./utils');
-
-function GeneralView(parentContainer, xInit, yInit, width, height, timeBegin, timeEnd, intervalWidth, intervalHeight, maxCellHeight, categories){
- var _this = this;
- this.container = new PIXI.DisplayObjectContainer();
- this.container.position.x = xInit;
- this.container.position.y = yInit;
- this.container.width = width;
- this.container.height = height;
- parentContainer.addChild(this.container);
-
- this.timeBegin = timeBegin;
- this.timeEnd = timeEnd;
- this.duration = (timeEnd - timeBegin)/1000
- this.width = width;
- this.height = height;
- this.intervalHeight = intervalHeight;
- this.intervalWidth = intervalWidth;
- this.maxCellHeight = maxCellHeight;
- this.intervalDuration = (intervalWidth*this.duration/width);
-
-
- //Initialise the list of step
- //each cell will contain the list categories and the number of annotations per categories
- this.cells = []
- for (var i=0; i<(width/intervalWidth) ; i++){
- this.cells[i] = [];
- this.cells[i].x = i * this.intervalWidth;
- this.cells[i].totalAnnots = 0;
- this.cells[i].graphics = new PIXI.Graphics();
- this.container.addChild(this.cells[i].graphics);
- this.cells[i].categories = {};
-
- for (var category in categories){
- this.cells[i].categories[category] = {
- "count": 0,
- "color": categories[category]
- };
- }
- }
- // draw temp line to locate the middle of the container
- var graphics = new PIXI.Graphics();
- graphics.beginFill(0x000000)
- .lineStyle(1, 0x000000)
- .moveTo(xInit, (-this.height/2) )
- .lineTo(this.width, (-this.height/2))
- .endFill();
- this.container.addChild(graphics);
-
- //Add Annotation to the TimeLine
- this.addAnnot = function(category, time){
- console.log(this.timeEnd);
- console.log(time);
- if (this.timeEnd < time){
- return;
- }
- var i = Math.floor((time-this.timeBegin)/(1000*this.intervalDuration));
- this.cells[i].categories[category].count += 1;
- this.cells[i].totalAnnots +=1;
- this.redrawCell(this.cells[i]);
- };
-
- //Draw the cellule
- this.redrawCell = function(cell){
- var x = cell.x;
- var y = -this.height/2;
- cell.graphics.clear();
-
- //Check if total height is higher than Max Cell Height
- if ((cell.totalAnnots*this.intervalHeight) > this.maxCellHeight){
- var heightStep = this.maxCellHeight/cell.totalAnnots;
- } else {
- var heightStep = this.intervalHeight;
- }
- //Draw the rect depending on the height step calculated
- for (var category in cell.categories){
- cell.graphics.beginFill(cell.categories[category].color)
- .drawRect(x, y, this.intervalWidth, -cell.categories[category].count * heightStep)
- .endFill();
- y -= cell.categories[category].count*heightStep;
- }
- }
-}
-
-module.exports = GeneralView;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annotviz/app/js/logger.js Tue Jan 20 18:37:51 2015 +0100
@@ -0,0 +1,45 @@
+/**
+* js/wswrapper.js
+*
+* simple logger service
+*
+*/
+
+/* global document: false */
+
+'use strict';
+
+function HtmlLogger(doLog, container) {
+
+ var logContainer = container;
+ if(typeof(container) === 'string') {
+ logContainer = document.getElementById(container);
+ }
+ if(!doLog) {
+ document.body.removeChild(logContainer);
+ logContainer = undefined;
+ }
+
+
+ this.log = function(msg) {
+ if(doLog && logContainer) {
+ logContainer.innerHTML += msg + '\n';
+ logContainer.scrollTop = logContainer.scrollHeight;
+ }
+ };
+}
+
+function ConsoleLogger(doLog) {
+
+ this.log = function(msg) {
+ if(doLog) {
+ console.log(msg);
+ }
+ }
+
+}
+
+module.exports = {
+ HtmlLogger: HtmlLogger,
+ ConsoleLogger: ConsoleLogger
+};
--- a/client/annotviz/app/js/main.js Tue Jan 20 12:00:40 2015 +0100
+++ b/client/annotviz/app/js/main.js Tue Jan 20 18:37:51 2015 +0100
@@ -7,304 +7,20 @@
'use strict';
-
-var PIXI = require('pixi');
-var rgb2hex = require('./utils');
-
-// Config vars
-var horizontalView = false;
-var logger = false;
-var sceneWidth = 1920;
-var sceneHeight = 1080;
-var prSize1 = 435;
-var prSize2 = 435;
-var prSize3 = 300;
-var sceneBgColor = 0xFFFFFF;
-var lineColor = 0x444444;
-if (horizontalView){
- var pixelsPerSecond1 = Math.floor(sceneWidth / 10); // nb of pixels per second
-} else{
- var pixelsPerSecond1 = Math.floor(sceneHeight / 10); // nb of pixels per second
-}
-var manualFramerate = pixelsPerSecond1 / 4;
-if (horizontalView){
- var pixelsPerSecond2 = Math.floor(sceneWidth / 60); // nb of pixels per second
-} else {
- var pixelsPerSecond2 = Math.floor(sceneHeight / 60); // nb of pixels per second
-}
-var pixelsPerSecond3 = Math.floor(sceneHeight / 60); // nb of pixels per second
-var lineInterval = 5000; // means line every 5 seconds
-var nbLines = -1;
-var noteHeight = 110;
-var noteColors = [0xB90000, 0x4BDD71, 0xAF931E, 0x1C28BA, 0x536991];
-var colorsReg = {};
-// Vars
-var noteDict = [];
-// Timecode method
-var timePageLoaded = Date.now();
-var offsetMusic = false;
-var categoriesColor = {
- "ntm" : rgb2hex(205,200,63),
- "iam" : rgb2hex(205,200,63),
- "hip" : rgb2hex(205,200,63),
- "hop" : rgb2hex(205,200,63),
- "rock" : rgb2hex(222,139,83),
- "rap" : rgb2hex(222,139,83),
- "classic" : rgb2hex(222,139,83),
- "drums" : rgb2hex(197,163,202),
- "guitar" : rgb2hex(197,163,202),
- "bass" : rgb2hex(121,187,146),
- "default": rgb2hex(128,128,128)
-};
-
-//create an new instance of a pixi stage
-var stage = new PIXI.Stage(sceneBgColor);
-
-//create a renderer instance.
-var renderer = PIXI.autoDetectRenderer(sceneWidth, sceneHeight);
-
-//add the renderer view element to the DOM
-document.getElementById('canvasContainer').appendChild(renderer.view);
-
-var uberContainer = new PIXI.DisplayObjectContainer();
-if (horizontalView){
- uberContainer.position.x = Math.floor(sceneWidth*9/10);
- uberContainer.position.y = 0;
-} else {
- uberContainer.position.x = 0;
- uberContainer.position.y = Math.floor(sceneHeight*9/10);
-}
-stage.addChild(uberContainer);
-
-/* ---------------------------------------------------------------- */
-/* ------------------- Init Pianoroll containers ------------------ */
-/* ---------------------------------------------------------------- */
-
-var PianoRoll = require('./pianoroll.js')
+var doubleroll = require('./doubleroll');
+var annotsroll = require('./annotsroll');
+var annotstimeline = require('./annotstimeline');
+var stageview = require('./stageview');
+var wswrapper = require('./wswrapper');
+var logger = require('./logger');
-var containerList = [];
-
-if (horizontalView){
- containerList.push(new PianoRoll(uberContainer, 0, 0, prSize1, true, pixelsPerSecond1, sceneWidth, noteColors, colorsReg, lineColor, lineInterval, offsetMusic, prSize1 / 128, horizontalView));
- containerList.push(new PianoRoll(uberContainer, 0, prSize1, prSize2, false, pixelsPerSecond2, sceneWidth, noteColors, colorsReg, lineColor, lineInterval, offsetMusic, prSize2 / 128, horizontalView));
-} else {
-// containerList.push(new PianoRoll(uberContainer, sceneWidth - prSize1, 0, sceneHeight, true, pixelsPerSecond1, prSize1, noteColors, colorsReg, lineColor, lineInterval, offsetMusic, prSize1 / 128, horizontalView));
-// containerList.push(new PianoRoll(uberContainer, sceneWidth - (prSize1 + prSize2), 0, sceneHeight, false, pixelsPerSecond2, prSize2, noteColors, colorsReg, lineColor, lineInterval, offsetMusic, prSize2 / 128, horizontalView));
- containerList.push(new PianoRoll(uberContainer, sceneWidth - prSize1, 0, sceneHeight, false, pixelsPerSecond2, prSize2, noteColors, colorsReg, lineColor, lineInterval, offsetMusic, prSize2 / 128, horizontalView));
-}
-
-// Line between two containers
-var graphics = new PIXI.Graphics();
-graphics.beginFill(0xFFFF00);
-graphics.lineStyle(1, lineColor);
-if (horizontalView){
- graphics.moveTo(0, prSize1);
- graphics.lineTo(sceneWidth, prSize1);
-} else {
- graphics.moveTo(sceneWidth - prSize1, 0);
- graphics.lineTo(sceneWidth - prSize1, sceneHeight);
- graphics.moveTo(sceneWidth - (prSize1 + prSize3), 0);
- graphics.lineTo(sceneWidth - (prSize1 + prSize3), sceneHeight);
-}
-graphics.endFill();
-stage.addChild(graphics);
-
-function addNotes(data){
- if(!offsetMusic){
- // get difference between the current note timecode and my zero to set the difference between the canvas's zero and the music's zero
- // in order to place in real time
- var now = Date.now();
- var timeBetweenNowAndStart = now - timePageLoaded;
- offsetMusic = timeBetweenNowAndStart - data.content[1];
- }
- var note = data.content[3];
- var velocity = data.content[4];
- if(velocity===0){
- if(typeof noteDict[data.content[2]][note]!=='undefined'){
- // We close the note in container one
- var duration = data.content[1] - noteDict[data.content[2]][note].ts;
- for(var i=0;i<containerList.length;i++){
- // addNote(note, startTime, duration, velocity, canal)
- containerList[i].addNote(note, noteDict[data.content[2]][note].ts, duration, noteDict[data.content[2]][note].velocity, data.content[2]);
- }
- // delete entry
- delete noteDict[data.content[2]][note];
- }
- }
- else{
- if(typeof noteDict[data.content[2]]==='undefined'){
- noteDict[data.content[2]] = {};
- }
- noteDict[data.content[2]][note] = {ts: data.content[1], velocity:velocity};
- }
-}
-
-function addLine(){
- var ts = new Date();
- for(var i=0;i<containerList.length;i++){
- containerList[i].addLine(ts);
- }
-}
-
-/* ---------------------------------------------------------------- */
-/* ------------------- Init AnnotsRoll containers ----------------- */
-/* ---------------------------------------------------------------- */
-
-var AnnotsRoll = require('./annotsRoll.js')
-
-var AnnotationRoll = new AnnotsRoll(uberContainer, sceneWidth - (prSize2 + prSize3), 0, prSize3 + prSize2, sceneHeight, prSize3, pixelsPerSecond3, lineInterval);
-
-/* ---------------------------------------------------------------- */
-/* ------------------- Init generalView container ----------------- */
-/* ---------------------------------------------------------------- */
+var _ = require('lodash');
-var GeneralView = require('./generalView.js')
-
-var GeneralRoll = new GeneralView(uberContainer, 0, 0, sceneWidth - (prSize2 + prSize3), sceneHeight, Date.now(), Date.now() + 300000, 30, 5, 100, categoriesColor);
-
-
-function addAnnots(data){
- var title = data.content.category.label;
- var code = data.content.category.code;
- var user = data.content.user;
- if (typeof(categoriesColor[code]) != 'undefined'){
- var color = categoriesColor[code];
- }
- else {
- var code = "default";
- var color = categoriesColor[code];
- }
-
- AnnotationRoll.addAnnot(title, user, color);
- GeneralRoll.addAnnot(code, Date.now());
-}
-
-/* ---------------------------------------------------------------- */
-/* ----------------------- Socket management ---------------------- */
-/* ---------------------------------------------------------------- */
-
-var sock = null;
-var sock2 = null;
-var ellog = null;
-function log(m) {
- if(logger){
- ellog.innerHTML += m + '\n';
- ellog.scrollTop = ellog.scrollHeight;
- }
-}
-window.onload = function(){
-
- if(logger){
- ellog = document.getElementById('log');
- }
- else{
- document.body.removeChild(document.getElementById('log'));
- }
-
- var wsuriInit;
- var wsuri;
- var wsuri2;
-
- if (window.location.protocol === 'file:') {
- wsuriInit = 'ws://127.0.0.1:8090/broadcast';
- } else {
- wsuriInit = 'ws://' + window.location.hostname + ':8090/broadcast';
- }
- wsuri = wsuriInit + '?channel=PIANOROLL&event_code='+eventCode;
- wsuri2 = wsuriInit + '?channel=ANNOT&event_code='+eventCode;
-
- if ('WebSocket' in window) {
- sock = new WebSocket(wsuri);
- sock2 = new WebSocket(wsuri2);
- } else if ('MozWebSocket' in window) {
- sock = new MozWebSocket(wsuri);
- sock2 = new WebSocket(wsuri2);
- } else {
- log('Browser does not support WebSocket!');
- window.location = 'http://autobahn.ws/unsupportedbrowser';
- }
-
- if (sock) {
- sock.onopen = function(){
- if(logger){
- log('Connected to ' + wsuri);
- }
- };
-
- sock.onclose = function(e) {
- if(logger){
- log('Connection closed (wasClean = ' + e.wasClean + ', code = ' + e.code + ', reason = \'' + e.reason + '\')');
- }
- sock = null;
- };
-
- sock.onmessage = function(e) {
- if(logger){
- log('Got message: ' + e.data);
- }
- addNotes(JSON.parse(e.data));
- };
- }
-
- if (sock2) {
- sock2.onopen = function(){
- if(logger){
- log('Connected to ' + wsuri);
- }
- };
-
- sock2.onclose = function(e) {
- if(logger){
- log('Connection closed (wasClean = ' + e.wasClean + ', code = ' + e.code + ', reason = \'' + e.reason + '\')');
- }
- sock2 = null;
- };
-
- sock2.onmessage = function(e) {
- if(logger){
- log('Got message: ' + e.data);
- }
-// console.log(e);
- addAnnots(JSON.parse(e.data));
- };
- }
-};
-
-function replaceContainers(){
- var diff = (Date.now() - timePageLoaded)/1000;// nb of seconds since page loaded
-
- for(var i=0;i<containerList.length;i++){
- containerList[i].moveTo(-diff);
- AnnotationRoll.moveTo(-diff);
- }
-
- renderer.render(stage);
-}
-
-/* ---------------------------------------------------------------- */
-/* ---------------------------- Main ------------------------------ */
-/* ---------------------------------------------------------------- */
-
-// Init page and intervals
-addLine();
-var moveInterval = window.setInterval(replaceContainers, 1000/manualFramerate);
-var verticalLinesInterval = window.setInterval(addLine, lineInterval);
-
-// Little inteval to show time
-var nbSec = 0;
-var mySpan = document.getElementById('myspan');
-function updateTime(){
- nbSec++;
- var hours = parseInt( nbSec / 3600 ) % 24;
- var minutes = parseInt( nbSec / 60 ) % 60;
- var seconds = nbSec % 60;
- var timeStr = (hours < 10 ? '0' + hours : hours) + ':' + (minutes < 10 ? '0' + minutes : minutes) + ':' + (seconds < 10 ? '0' + seconds : seconds);
- mySpan.innerHTML = timeStr;
-}
-var secondInterval = window.setInterval(updateTime, 1000);
-
-module.exports = {
- moveInterval: moveInterval,
- verticalLinesInterval: verticalLinesInterval,
- secondInterval: secondInterval
-};
+module.exports = _({})
+ .extend(doubleroll)
+ .extend(annotsroll)
+ .extend(annotstimeline)
+ .extend(stageview)
+ .extend(wswrapper)
+ .extend(logger)
+ .value();
\ No newline at end of file
--- a/client/annotviz/app/js/pianoroll.js Tue Jan 20 12:00:40 2015 +0100
+++ b/client/annotviz/app/js/pianoroll.js Tue Jan 20 18:37:51 2015 +0100
@@ -7,47 +7,46 @@
'use strict';
+
var PIXI = require('pixi');
var randomColor = require('randomColor');
+var _ = require('lodash');
-function PianoRoll(parentContainer, xInit, yInit, height, linesDown, pixelsPerSecond, width, noteColors, colorsReg, lineColor, lineInterval, offsetMusic, noteHeight, horizontalView){
+var NTP_EPOCH_DELTA = 2208988800; //c.f. RFC 868
+
+function PianoRoll(options) {
var _this = this;
this.container = new PIXI.DisplayObjectContainer();
- this.container.position.x = xInit;
- this.container.position.y = yInit;
- if (!horizontalView){
- this.container.width = width;
- }
- parentContainer.addChild(this.container);
+ this.container.x = options.xInit;
+ this.container.y = options.yInit;
+ options.parentContainer.addChild(this.container);
- this.linesDown = linesDown;
- this.height = height;
- this.pixelsPerSecond = pixelsPerSecond;
- this.width = width;
- this.noteColors = noteColors;
- this.colorsReg = colorsReg || {};
- this.lineColor = lineColor;
- this.lineInterval = lineInterval;
- this.offsetMusic = offsetMusic || 0;
- this.noteHeight = noteHeight;
+ var orientation = options.orientation;
+ var isHorizontal = (orientation !== 'vertical');
- this.addNote = function(note, startTime, duration, velocity, canal){
- var begin = (this.offsetMusic + startTime) * this.pixelsPerSecond / 1000;
- if (horizontalView){
- var width = duration * this.pixelsPerSecond / 1000;
- if((begin+width) < (Math.abs(this.container.x) - this.width)) {
- // not visible. do nothing
- return;
- }
- } else {
- var height = duration * this.pixelsPerSecond / 1000;
- if((begin+height) < (Math.abs(this.container.y) - this.height)) {
- // not visible. do nothing
- return;
- }
- }
- // We draw the rectangle
- var graphics = new PIXI.Graphics();
+ this.linesDown = options.linesDown;
+ this.height = options.height;
+ this.pixelsPerSecond = options.pixelsPerSecond;
+ this.width = options.width;
+ this.noteColors = options.noteColors;
+ this.colorsReg = options.colorsReg || {};
+ this.lineColor = options.lineColor;
+ this.lineInterval = options.lineInterval;
+ this.offsetMusic = options.offsetMusic || false;
+ this.noteHeight = options.noteHeight;
+ this.noteDict = {};
+ this.startTs = options.startTs || Date.now();
+
+ var started = false;
+
+ var isHidden = function(child) {
+ // TODO: the origin point is an approximation. Should refine this
+ var globalPos = child.toGlobal(new PIXI.Point(0,0));
+ return ((globalPos.x + child.width) < 0) || ((globalPos.y + child.height) < 0) ;
+ };
+
+ //TODO: I do not like the "regColor" object. This should not be global, but local
+ this.getColor = function(canal) {
var color = this.colorsReg[canal];
if(typeof(color) === 'undefined') {
var colorsRegSize = Object.keys(this.colorsReg).length;
@@ -58,39 +57,104 @@
color = this.colorsReg[canal] = parseInt(randomColor({ luminosity: 'light', hue: 'random', format:'hex'}).replace(/^#/, ''), 16);
}
}
- graphics.beginFill(color, (velocity / 128));
- if (horizontalView){
- var y = (128-note) * this.height / 128; // (128-note) because y = 0 is for note = 128 and y = 128 for note = 0
- graphics.drawRect(0, Math.floor(y - (noteHeight/2) + ((this.height / 128)/2)), width, noteHeight);
- graphics.endFill();
- graphics.x = begin;
- } else {
- var x = (128-note) * this.width / 128; // (128-note) because y = 0 is for note = 128 and y = 128 for note = 0
- graphics.drawRect(Math.floor(x - (noteHeight/2) + ((this.width / 128)/2)), 0, noteHeight, height);
- graphics.endFill();
- graphics.y = begin;
+ return color;
+ };
+
+ this.getNoteRect = function(x, y, color, alpha, width, height) {
+ var graphics = new PIXI.Graphics();
+ graphics.beginFill(color, alpha);
+ graphics.drawRect(0, 0, width, height);
+ graphics.endFill();
+ graphics.x = x;
+ graphics.y = y;
+ graphics.width = width;
+ graphics.height = height;
+ return graphics;
+ };
+
+ this.addNoteRaw = 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];
+
+ this.addNote(note, ts, sessionTs, velocity, channel, 0);
+ };
+
+ this.addNote = function(note, startTime, sessionTs, velocity, channel, duration) {
+
+ var ts = startTime;
+ if(this.offsetMusic) {
+ ts = this.startTs + sessionTs;
}
- this.container.addChild(graphics);
+
+ var noteDuration = duration;
+ var noteVelocity = velocity;
+ var graphics;
+ if(!duration) {
+ if(typeof this.noteDict[channel]==='undefined'){
+ this.noteDict[channel] = {};
+ }
+ if(velocity===0) {
+ if(typeof this.noteDict[channel][note] !== 'undefined') {
+ var noteDef = this.noteDict[channel][note];
+ delete this.noteDict[channel][note];
+ noteDuration = sessionTs - noteDef.sessionTs;
+ graphics = noteDef.graphics;
+ noteVelocity = noteDef.velocity;
+ ts = noteDef.ts;
+ }
+ }
+ else {
+ noteDuration = Date.now() - ts;
+ this.noteDict[channel][note] = { ts: ts, velocity: velocity, sessionTs: sessionTs};
+ }
+ }
+
+
+ if(!this.offsetMusic || velocity===0) {
+
+ var width = noteDuration * this.pixelsPerSecond / 1000;
+ if(!graphics) {
+ var x = (ts-this.startTs) * this.pixelsPerSecond / 1000;
+ if((x+width) < (Math.abs(this.container.x) - this.width)) {
+ // not visible. do nothing
+ return;
+ }
+ var y = Math.floor((128-note+0.5) * this.height / 128 - (this.noteHeight/2));
+ var color = this.getColor(channel);
+ var alpha = (noteVelocity / 128);
+
+ graphics = this.getNoteRect(x, y, color, alpha, width, this.noteHeight);
+ this.container.addChild(graphics);
+ }
+ else {
+ graphics.width = width;
+ }
+
+ if(!duration && velocity) {
+ this.noteDict[channel][note].graphics = graphics;
+ }
+ }
};
this.addLine = function(ts){
- var graphics = new PIXI.Graphics();
- if (horizontalView){
- var x = -this.container.x;
- var y = this.linesDown ? this.height - 20 : 0;
- } else {
- var x = this.linesDown ? 0 : this.width - 20 ;
- var y = -this.container.y;
+
+ if(typeof(ts) === 'undefined') {
+ ts = new Date();
}
- graphics.beginFill(0xFFFF00);
- graphics.lineStyle(1, this.lineColor);
- graphics.moveTo(x, y);
- if (horizontalView){
- graphics.lineTo(x, y + 20);
- } else {
- graphics.lineTo(x + 20, y);
- }
- graphics.endFill();
+ var x = -this.container.x;
+ var y = this.linesDown ? this.height - 20 : 0;
+
+ var graphics = new PIXI.Graphics()
+ .beginFill(0xFFFF00)
+ .lineStyle(1, this.lineColor)
+ .moveTo(0, 0)
+ .lineTo(0, 20)
+ .endFill();
+ graphics.x = x;
+ graphics.y = y;
this.container.addChild(graphics);
// Add text
//var totalSec = lineNb * this.lineInterval / 1000;
@@ -101,60 +165,63 @@
var fontObj = { font: '10pt Arial', fill: '#444444' };
var t = new PIXI.Text(timeStr, fontObj);
- if (horizontalView){
- t.x = x + 2;
- t.y = this.linesDown ? this.height - 15 : 2;
- } else {
- t.x = this.linesDown ? 2 : this.width - 55;
- t.y = y + 2;
+ if(isHorizontal) {
+ t.x = x + 2;
+ t.y = this.linesDown ? this.height - 15 : 2;
+ }
+ else {
+ t.rotation = -Math.PI/2;
+ t.x = x ;
+ t.y = this.linesDown ? this.height - 2 : t.width + 2;
}
this.container.addChild(t);
};
this.moveTo = function(diffTime){
- if (horizontalView){
- this.container.x = Math.floor(diffTime*this.pixelsPerSecond);
- } else {
- this.container.y = Math.floor(diffTime*this.pixelsPerSecond);
- }
+ var oldX = this.container.x;
+ this.container.x = Math.floor(diffTime*this.pixelsPerSecond);
+ var deltaX = Math.abs(oldX-this.container.x);
+ _.forOwn(this.noteDict, function(channelDict) {
+ _.forOwn(channelDict, function(noteDef) {
+ if(noteDef.graphics) {
+ noteDef.graphics.width = noteDef.graphics.width + deltaX;
+ }
+ });
+ });
+ };
+
+ this.move = function() {
+ var diff = (this.startTs - Date.now())/1000;
+ this.moveTo(diff);
};
this.removePassedObjets = function(){
- var nbChilds = _this.container.children.length;
- var i = 0, childIsNowDisplayed = false, childrenToRemove = [];
- while(i<nbChilds && !childIsNowDisplayed){
- var child = _this.container.children[i++];
- if(typeof(child) == 'undefined') {
- continue;
- }
- if (horizontalView){
- if((child.x + child.width) < (Math.abs(_this.container.x) - _this.width)){
- childrenToRemove.push(child);
- }
- else {
- childIsNowDisplayed = true;
- }
- } else {
- if((child.y + child.height) < (Math.abs(_this.container.y) - _this.height)){
- childrenToRemove.push(child);
- }
- else {
- childIsNowDisplayed = true;
- }
- }
- }
+ var childrenToRemove = [];
+ _(_this.container.children).forEach(function(child) {
+ return typeof(child) === 'undefined' ||
+ (isHidden(child) && childrenToRemove.push(child));
+ });
childrenToRemove.forEach(function(child) {
_this.container.removeChild(child);
});
};
- // remove notes each scene width
- //var removeInterval = window.setInterval(this.removePassedObjets, 1000 * sceneWidth / this.pixelsPerSecond );
- if (horizontalView){
- window.setInterval(this.removePassedObjets, 1000 * this.width / this.pixelsPerSecond );
- } else {
- window.setInterval(this.removePassedObjets, 1000 * this.height / this.pixelsPerSecond );
- }
+ this.start = function() {
+ if(!started) {
+ this.startTs = Date.now();
+ this.addLine();
+ started = true;
+ }
+ this.verticalLinesInterval = setInterval(function() { _this.addLine(); }, this.lineInterval);
+ this.cleanInterval = setInterval(function () { _this.removePassedObjets(); }, 1000 * this.width / this.pixelsPerSecond );
+ };
+
+ this.stop = function() {
+ //window.clearInterval(this.moveInterval);
+ clearInterval(this.verticalLinesInterval);
+ clearInterval(this.cleanInterval);
+ };
+
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annotviz/app/js/wswrapper.js Tue Jan 20 18:37:51 2015 +0100
@@ -0,0 +1,53 @@
+/**
+* js/wswrapper.js
+*
+* simple webservice wrapper to register callbacks on onmessage
+*
+*/
+
+/* global WebSocket: false */
+
+'use strict';
+
+function WsWrapper(wsurl, logger) {
+
+ var url = wsurl;
+ var sock = new WebSocket(url);
+ var loggerObj = logger;
+
+ var log = function(msg) {
+ if(loggerObj) {
+ loggerObj.log(msg);
+ }
+ };
+
+ var handlers = [];
+
+ sock.onopen = function() {
+ log('Connected to ' + url);
+ };
+
+ sock.onclose = function(e) {
+ log('Connection closed (wasClean = ' + e.wasClean + ', code = ' + e.code + ', reason = \'' + e.reason + '\')');
+ sock = null;
+ };
+
+ sock.onmessage = function(e) {
+ log('received ' + e.data);
+ var data = JSON.parse(e.data);
+ handlers.forEach(function(handler) {
+ handler(data);
+ });
+ };
+
+ this.message = function(handler) {
+ if(handler) {
+ handlers.push(handler);
+ }
+ };
+
+}
+
+module.exports = {
+ WsWrapper: WsWrapper
+};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annotviz/app/pianoroll_h.html Tue Jan 20 18:37:51 2015 +0100
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width,initial-scale=1">
+ <meta name="description" content="">
+ <meta name="author" content="I.R.I">
+ <link rel="shortcut icon" href="/img/favicon.ico">
+
+ <title>Horizontal Piano Roll</title>
+
+ <!-- Custom styles for this template -->
+ <link href="/css/annotviz.css" rel="stylesheet">
+</head>
+
+<body>
+ <h1>Horizontal Piano Roll</h1>
+ <noscript>You must enable JavaScript</noscript>
+ <div id="canvasContainer"></div>
+ <p>
+ <a href="#" onclick="stop(); return false;">stop intervals</a> -
+ <a href="#" onclick="start(); return false;">start intervals</a> -
+ temps écoulé : <span id="timeStarted"></span>
+ </p>
+ <pre id="log"></pre>
+ <script src="/js/libs-annotviz.js"></script>
+ <script src="/js/annotviz.js"></script>
+ <script>
+ var annotationChannel = 'PIANOROLL';
+ var eventCode = 'test_1';
+ var 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 logger = new annotviz.HtmlLogger(false, 'log');
+
+ var stageView = new annotviz.StageView({
+ logger: logger
+ });
+
+ var doubleroll = new annotviz.DoubleRoll({
+ logger: logger,
+ stageView: stageView,
+ ws: new annotviz.WsWrapper(wsUri)
+ });
+
+ function stop() { stageView.stop(); }
+ function start() { stageView.start(); }
+
+ window.onload = function() {
+ stageView.init();
+ start();
+ }
+ </script>
+</body>
+</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/client/annotviz/app/pianoroll_v.html Tue Jan 20 18:37:51 2015 +0100
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width,initial-scale=1">
+ <meta name="description" content="">
+ <meta name="author" content="I.R.I">
+ <link rel="shortcut icon" href="/img/favicon.ico">
+
+ <title>Vertical Piano Roll</title>
+
+ <!-- Custom styles for this template -->
+ <link href="/css/annotviz.css" rel="stylesheet">
+</head>
+
+<body>
+ <h1>Vertical Piano Roll</h1>
+ <noscript>You must enable JavaScript</noscript>
+ <div id="canvasContainer"></div>
+ <p>
+ <a href="#" onclick="stop(); return false;">stop intervals</a> -
+ <a href="#" onclick="start(); return false;">start intervals</a> -
+ temps écoulé : <span id="timeStarted"></span>
+ </p>
+ <pre id="log"></pre>
+ <script src="/js/libs-annotviz.js"></script>
+ <script src="/js/annotviz.js"></script>
+ <script>
+ var annotationChannel = 'PIANOROLL';
+ var eventCode = 'test_1';
+ var 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 logger = new annotviz.HtmlLogger(false, 'log');
+
+ var stageView = new annotviz.StageView({
+ logger: logger
+ });
+
+ var doubleroll = new annotviz.DoubleRoll({
+ orientation: 'vertical',
+ logger: logger,
+ stageView: stageView,
+ ws: new annotviz.WsWrapper(wsUri)
+ });
+ function stop() { stageView.stop(); }
+ function start() { stageView.start(); }
+
+ window.onload = function() {
+ stageView.init();
+ start();
+ };
+
+ </script>
+</body>
+</html>
--- a/client/annotviz/bower.json Tue Jan 20 12:00:40 2015 +0100
+++ b/client/annotviz/bower.json Tue Jan 20 18:37:51 2015 +0100
@@ -3,6 +3,7 @@
"version": "0.0.0",
"dependencies": {
"randomColor": "davidmerfield/randomColor#~0.1.1",
- "pixi": "~2.2.3"
+ "pixi": "~2.2.3",
+ "lodash": "~2.4.1"
}
}
--- a/client/annotviz/gulp/tasks/browserify.js Tue Jan 20 12:00:40 2015 +0100
+++ b/client/annotviz/gulp/tasks/browserify.js Tue Jan 20 18:37:51 2015 +0100
@@ -15,6 +15,7 @@
return browserify({debug: true})
.require('./app/lib/pixi/bin/pixi.js', { expose: 'pixi' })
.require('./app/lib/randomColor/randomColor.js', {expose: 'randomColor'})
+ .require('./app/lib/lodash/dist/lodash.js', {expose: 'lodash'})
.bundle()
.pipe(source('libs-'+p.name+'.js'))
.pipe(gulp.dest(config.dist + '/js/'));
@@ -26,6 +27,7 @@
.add('./app/js/main.js')
.external('pixi')
.external('randomColor')
+ .external('lodash')
.transform(partialify) // Transform to allow requireing of templates
.bundle()
.pipe(source(p.name+'.js'))
--- a/client/pianoroll/app/js/main.js Tue Jan 20 12:00:40 2015 +0100
+++ b/client/pianoroll/app/js/main.js Tue Jan 20 18:37:51 2015 +0100
@@ -84,7 +84,7 @@
}
var note = data.content[3];
var velocity = data.content[4];
- if(velocity===0){
+ if(velocity===0) {
if(typeof noteDict[data.content[2]][note]!=='undefined'){
// We close the note in container one
//console.log("coucou 2", data);
--- a/utils/pianoroll-client.py Tue Jan 20 12:00:40 2015 +0100
+++ b/utils/pianoroll-client.py Tue Jan 20 18:37:51 2015 +0100
@@ -7,6 +7,7 @@
import argparse
import csv
+import signal
import time
import ntplib
@@ -19,7 +20,7 @@
"""
Example that sends UDP messages.
"""
- def __init__(self, port, host, address, rows, shift):
+ def __init__(self, port, host, address, rows, shift, token):
self.port = port
self.host = host
self.client = async.DatagramClientProtocol()
@@ -27,6 +28,7 @@
self.rows = rows
self.address = address
self.shift = shift
+ self.token = token
reactor.callLater(0, self.send_messages)
def _send(self, element):
@@ -36,19 +38,31 @@
def send_messages(self):
t0 = time.time()
+ #tc = 0
for row in self.rows:
+ if not self.token.running:
+ break
if self.shift:
- row[0] = ntplib.system_to_ntp_time(t0 + float(row[1])/10**3)
+ row[0] = ntplib.system_to_ntp_time(t0 + float(row[1])/1000.0)
row_conv = [ osc.TimeTagArgument(float(row[0]))] + [osc.IntArgument(int(a)) for a in row[1:]]
- #time.sleep((row_conv[1].value-tc)/10**3)
- time.sleep(0.1)
- #tc = row_conv[1].value
+ #time.sleep((row_conv[1].value-tc)/1000.0)
+ sleep_time = t0+float(row[1])/1000.0-time.time()
+ if sleep_time > 0:
+ time.sleep(sleep_time)
+ #time.sleep(0.1)
+ tc = row_conv[1].value
self._send(osc.Message(self.address,*row_conv))
print("Goodbye.")
reactor.callLater(0.1, reactor.stop)
+class Token(object):
+ def __init__(self):
+ self.running = True
+
if __name__ == "__main__":
+ token = Token()
+
parser = argparse.ArgumentParser(description='Simulate an (osc) pianoroll client.')
parser.add_argument('datafile', metavar='DATAFILE', help='The file containing the pianoroll data (CSV).')
parser.add_argument('-e', '--event', dest='event', metavar='EVENT', required=True, help='the event code.')
@@ -56,8 +70,16 @@
args = parser.parse_args()
+ def customHandler(signum, _):
+ print("Got signal: %s" % signum)
+ token.running = False
+ if reactor.running:
+ reactor.callFromThread(reactor.stop) # to stop twisted code when in the reactor loop
+ signal.signal(signal.SIGINT, customHandler)
+
+
with open(args.datafile, 'rU') as datafile:
reader = csv.reader(datafile, delimiter=' ')
- app = UDPSenderApplication(9090, "127.0.0.1", "/pianoroll/%s/" % args.event, list(reader), args.shift)
+ app = UDPSenderApplication(9090, "127.0.0.1", "/pianoroll/%s/" % args.event, list(reader), args.shift, token)
reactor.run()