extended MIDI support. Some new general purpose nodes like sequencer, string, cast to number.

This commit is contained in:
tamat
2019-01-05 23:54:44 +01:00
parent 8dce8acb91
commit ac11db37b4
16 changed files with 2274 additions and 837 deletions

View File

@@ -1719,11 +1719,16 @@ LGraph.prototype.onNodeTrace = function(node, msg, color)
input|output: every connection
+ { name:string, type:string, pos: [x,y]=Optional, direction: "input"|"output", links: Array });
flags:
general properties:
+ clip_area: if you render outside the node, it will be cliped
+ unsafe_execution: not allowed for safe execution
+ skip_repeated_outputs: when adding new outputs, it wont show if there is one already connected
+ resizable: if set to false it wont be resizable with the mouse
+ horizontal: slots are distributed horizontally
+ widgets_up: widgets start from the top of the node
flags object:
+ collapsed: if it is collapsed
supported callbacks:
+ onAdded: when added to graph
@@ -2168,13 +2173,16 @@ LGraphNode.prototype.getInputOrProperty = function( name )
return this.properties ? this.properties[name] : null;
for(var i = 0, l = this.inputs.length; i < l; ++i)
if(name == this.inputs[i].name)
{
var input_info = this.inputs[i];
if(name == input_info.name && input_info.link != null)
{
var link_id = this.inputs[i].link;
var link = this.graph.links[ link_id ];
return link ? link.data : null;
var link = this.graph.links[ input_info.link ];
if(link)
return link.data;
}
return this.properties[name];
}
return this.properties[ name ];
}
@@ -3985,7 +3993,7 @@ LGraphCanvas.prototype.processMouseDown = function(e)
if(!this.connecting_node && !node.flags.collapsed && !this.live_mode)
{
//Search for corner for resize
if( !skip_action && node.flags.resizable !== false && isInsideRectangle( e.canvasX, e.canvasY, node.pos[0] + node.size[0] - 5, node.pos[1] + node.size[1] - 5 ,10,10 ))
if( !skip_action && node.resizable !== false && isInsideRectangle( e.canvasX, e.canvasY, node.pos[0] + node.size[0] - 5, node.pos[1] + node.size[1] - 5 ,10,10 ))
{
this.resizing_node = node;
this.canvas.style.cursor = "se-resize";
@@ -5535,6 +5543,8 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
var shape = node._shape || LiteGraph.BOX_SHAPE;
var size = temp_vec2;
temp_vec2.set( node.size );
var horizontal = node.horizontal || node.flags.horizontal;
if( node.flags.collapsed )
{
ctx.font = this.inner_text_font;
@@ -5544,7 +5554,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
size[1] = 0;
}
if( node.flags.clip_area ) //Start clipping
if( node.clip_area ) //Start clipping
{
ctx.save();
ctx.beginPath();
@@ -5562,7 +5572,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
ctx.shadowColor = "transparent";
//connection slots
ctx.textAlign = node.flags.horizontal ? "center" : "left";
ctx.textAlign = horizontal ? "center" : "left";
ctx.font = this.inner_text_font;
var render_text = this.scale > 0.6;
@@ -5597,8 +5607,12 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
ctx.beginPath();
if (slot.type === LiteGraph.EVENT || slot.shape === LiteGraph.BOX_SHAPE) {
ctx.rect((pos[0] - 6) + 0.5, (pos[1] - 5) + 0.5, 14, 10);
if (slot.type === LiteGraph.EVENT || slot.shape === LiteGraph.BOX_SHAPE)
{
if (horizontal)
ctx.rect((pos[0] - 5) + 0.5, (pos[1] - 8) + 0.5, 10, 14);
else
ctx.rect((pos[0] - 6) + 0.5, (pos[1] - 5) + 0.5, 14, 10);
} else if (slot.shape === LiteGraph.ARROW_SHAPE) {
ctx.moveTo(pos[0] + 8, pos[1] + 0.5);
ctx.lineTo(pos[0] - 4, (pos[1] + 6) + 0.5);
@@ -5617,7 +5631,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
if(text)
{
ctx.fillStyle = LiteGraph.NODE_TEXT_COLOR;
if( node.flags.horizontal || slot.dir == LiteGraph.UP )
if( horizontal || slot.dir == LiteGraph.UP )
ctx.fillText(text,pos[0],pos[1] - 10);
else
ctx.fillText(text,pos[0] + 10,pos[1] + 5);
@@ -5629,7 +5643,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
if(this.connecting_node)
ctx.globalAlpha = 0.4 * editor_alpha;
ctx.textAlign = node.flags.horizontal ? "center" : "right";
ctx.textAlign = horizontal ? "center" : "right";
ctx.strokeStyle = "black";
if(node.outputs)
for(var i = 0; i < node.outputs.length; i++)
@@ -5646,8 +5660,12 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
ctx.beginPath();
//ctx.rect( node.size[0] - 14,i*14,10,10);
if (slot.type === LiteGraph.EVENT || slot.shape === LiteGraph.BOX_SHAPE) {
ctx.rect((pos[0] - 6) + 0.5,(pos[1] - 5) + 0.5,14,10);
if (slot.type === LiteGraph.EVENT || slot.shape === LiteGraph.BOX_SHAPE)
{
if( horizontal )
ctx.rect((pos[0] - 5) + 0.5,(pos[1] - 8) + 0.5,10,14);
else
ctx.rect((pos[0] - 6) + 0.5,(pos[1] - 5) + 0.5,14,10);
} else if (slot.shape === LiteGraph.ARROW_SHAPE) {
ctx.moveTo(pos[0] + 8, pos[1] + 0.5);
ctx.lineTo(pos[0] - 4, (pos[1] + 6) + 0.5);
@@ -5672,7 +5690,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
if(text)
{
ctx.fillStyle = LiteGraph.NODE_TEXT_COLOR;
if( node.flags.horizontal || slot.dir == LiteGraph.DOWN )
if( horizontal || slot.dir == LiteGraph.DOWN )
ctx.fillText(text,pos[0],pos[1] - 8);
else
ctx.fillText(text, pos[0] - 10,pos[1] + 5);
@@ -5685,7 +5703,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
if(node.widgets)
{
if( node.flags.horizontal || node.flags.widgets_up )
if( horizontal || node.widgets_up )
max_y = 2;
this.drawNodeWidgets( node, max_y, ctx, (this.node_widget && this.node_widget[0] == node) ? this.node_widget[1] : null );
}
@@ -5726,7 +5744,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
{
var x = 0;
var y = LiteGraph.NODE_TITLE_HEIGHT * -0.5; //center
if( node.flags.horizontal )
if( horizontal )
{
x = node._collapsed_width * 0.5;
y = -LiteGraph.NODE_TITLE_HEIGHT;
@@ -5750,7 +5768,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
{
var x = node._collapsed_width;
var y = LiteGraph.NODE_TITLE_HEIGHT * -0.5; //center
if( node.flags.horizontal )
if( horizontal )
{
x = node._collapsed_width * 0.5;
y = 0;
@@ -5773,7 +5791,7 @@ LGraphCanvas.prototype.drawNode = function(node, ctx )
}
}
if(node.flags.clip_area)
if(node.clip_area)
ctx.restore();
ctx.globalAlpha = 1.0;
@@ -5869,30 +5887,33 @@ LGraphCanvas.prototype.drawNodeShape = function( node, ctx, size, fgcolor, bgcol
}
//title box
if (shape == LiteGraph.ROUND_SHAPE || shape == LiteGraph.CIRCLE_SHAPE || shape == LiteGraph.CARD_SHAPE)
if(node.flags.render_box !== false)
{
if( this.scale > 0.5 )
if (shape == LiteGraph.ROUND_SHAPE || shape == LiteGraph.CIRCLE_SHAPE || shape == LiteGraph.CARD_SHAPE)
{
ctx.fillStyle = "black";
if( this.scale > 0.5 )
{
ctx.fillStyle = "black";
ctx.beginPath();
ctx.arc(title_height *0.5, title_height * -0.5, (title_height - 8) *0.5,0,Math.PI*2);
ctx.fill();
}
ctx.fillStyle = node.boxcolor || LiteGraph.NODE_DEFAULT_BOXCOLOR;
ctx.beginPath();
ctx.arc(title_height *0.5, title_height * -0.5, (title_height - 8) *0.5,0,Math.PI*2);
ctx.arc(title_height *0.5, title_height * -0.5, (title_height - 8) *0.4,0,Math.PI*2);
ctx.fill();
}
ctx.fillStyle = node.boxcolor || LiteGraph.NODE_DEFAULT_BOXCOLOR;
ctx.beginPath();
ctx.arc(title_height *0.5, title_height * -0.5, (title_height - 8) *0.4,0,Math.PI*2);
ctx.fill();
}
else
{
if( this.scale > 0.5 )
else
{
ctx.fillStyle = "black";
ctx.fillRect(4,-title_height + 4,title_height - 8,title_height - 8);
if( this.scale > 0.5 )
{
ctx.fillStyle = "black";
ctx.fillRect(4,-title_height + 4,title_height - 8,title_height - 8);
}
ctx.fillStyle = node.boxcolor || LiteGraph.NODE_DEFAULT_BOXCOLOR;
ctx.fillRect(5,-title_height + 5,title_height - 10,title_height - 10);
}
ctx.fillStyle = node.boxcolor || LiteGraph.NODE_DEFAULT_BOXCOLOR;
ctx.fillRect(5,-title_height + 5,title_height - 10,title_height - 10);
}
ctx.globalAlpha = old_alpha;
@@ -6341,6 +6362,7 @@ LGraphCanvas.prototype.drawNodeWidgets = function( node, posY, ctx, active_widge
ctx.fillText( w.value, width - 40, y + H*0.7 );
}
break;
case "string":
case "text":
ctx.textAlign = "left";
ctx.strokeStyle = "#AAA";
@@ -6463,6 +6485,7 @@ LGraphCanvas.prototype.processNodeWidgets = function( node, pos, event, active_w
setTimeout( function(){ w.callback( w.value, that, node, pos ); }, 20 );
}
break;
case "string":
case "text":
if( event.type == "mousedown" )
this.prompt( "Value", w.value, (function(v){ this.value = v; if(w.callback) w.callback(v, that, node ); }).bind(w), event );

View File

@@ -334,36 +334,55 @@ LiteGraph.registerNodeType("graph/output", GlobalOutput);
//Constant
function Constant()
function ConstantNumber()
{
this.addOutput("value","number");
this.addProperty( "value", 1.0 );
this.editable = { property:"value", type:"number" };
}
Constant.title = "Const";
Constant.desc = "Constant value";
ConstantNumber.title = "Const Number";
ConstantNumber.desc = "Constant number";
Constant.prototype.setValue = function(v)
{
if( typeof(v) == "string") v = parseFloat(v);
this.properties["value"] = v;
this.setDirtyCanvas(true);
};
Constant.prototype.onExecute = function()
ConstantNumber.prototype.onExecute = function()
{
this.setOutputData(0, parseFloat( this.properties["value"] ) );
}
Constant.prototype.onDrawBackground = function(ctx)
ConstantNumber.prototype.onDrawBackground = function(ctx)
{
//show the current value
this.outputs[0].label = this.properties["value"].toFixed(3);
}
LiteGraph.registerNodeType("basic/const", Constant);
LiteGraph.registerNodeType("basic/const", ConstantNumber);
function ConstantString()
{
this.addOutput("","string");
this.addProperty( "value", "" );
this.widget = this.addWidget("text","value","", this.setValue.bind(this) );
this.widgets_up = true;
}
ConstantString.title = "Const String";
ConstantString.desc = "Constant string";
ConstantString.prototype.setValue = function(v)
{
this.properties.value = v;
}
ConstantString.prototype.onPropertyChanged = function(name,value)
{
this.widget.value = value;
}
ConstantString.prototype.onExecute = function()
{
this.setOutputData(0, this.properties["value"] );
}
LiteGraph.registerNodeType("basic/string", ConstantString );
//Watch a value in the editor

View File

@@ -20,6 +20,39 @@ LogEvent.prototype.onAction = function( action, param )
LiteGraph.registerNodeType("events/log", LogEvent );
//Sequencer for events
function Sequencer()
{
this.addInput("", LiteGraph.ACTION);
this.addInput("", LiteGraph.ACTION);
this.addInput("", LiteGraph.ACTION);
this.addInput("", LiteGraph.ACTION);
this.addInput("", LiteGraph.ACTION);
this.addInput("", LiteGraph.ACTION);
this.addOutput("", LiteGraph.EVENT);
this.addOutput("", LiteGraph.EVENT);
this.addOutput("", LiteGraph.EVENT);
this.addOutput("", LiteGraph.EVENT);
this.addOutput("", LiteGraph.EVENT);
this.addOutput("", LiteGraph.EVENT);
this.size = [120,30];
this.flags = { horizontal: true, render_box: false };
}
Sequencer.title = "Sequencer";
Sequencer.desc = "Trigger events when an event arrives";
Sequencer.prototype.getTitle = function() { return ""; }
Sequencer.prototype.onAction = function( action, param )
{
if(this.outputs)
for(var i = 0; i < this.outputs.length; ++i)
this.triggerSlot( i, param );
}
LiteGraph.registerNodeType("events/sequencer", Sequencer );
//Filter events
function FilterEvent()
{
@@ -59,6 +92,52 @@ FilterEvent.prototype.onAction = function( action, param )
LiteGraph.registerNodeType("events/filter", FilterEvent );
//Show value inside the debug console
function EventCounter()
{
this.addInput("inc", LiteGraph.ACTION);
this.addInput("dec", LiteGraph.ACTION);
this.addInput("reset", LiteGraph.ACTION);
this.addOutput("change", LiteGraph.EVENT);
this.addOutput("num", "number");
this.num = 0;
}
EventCounter.title = "Counter";
EventCounter.desc = "Counts events";
EventCounter.prototype.onAction = function(action, param)
{
var v = this.num;
if(action == "inc")
this.num += 1;
else if(action == "dec")
this.num -= 1;
else if(action == "reset")
this.num = 0;
if(this.num != v)
this.trigger("change",this.num);
}
EventCounter.prototype.onDrawBackground = function(ctx)
{
if(this.flags.collapsed)
return;
ctx.fillStyle = "#AAA";
ctx.font = "20px Arial";
ctx.textAlign = "center";
ctx.fillText( this.num, this.size[0] * 0.5, this.size[1] * 0.5 );
}
EventCounter.prototype.onExecute = function()
{
this.setOutputData(1,this.num);
}
LiteGraph.registerNodeType("events/counter", EventCounter );
//Show value inside the debug console
function DelayEvent()
{
@@ -142,15 +221,19 @@ TimerEvent.prototype.onDrawBackground = function()
TimerEvent.prototype.onExecute = function()
{
var dt = this.graph.elapsed_time * 1000; //in ms
var trigger = this.time == 0;
this.time += dt;
this.last_interval = Math.max(1, this.getInputOrProperty("interval") | 0);
if( this.time < this.last_interval || isNaN(this.last_interval) )
if( !trigger && ( this.time < this.last_interval || isNaN(this.last_interval)) )
{
if( this.inputs && this.inputs.length > 1 && this.inputs[1] )
this.setOutputData(1,false);
return;
}
this.triggered = true;
this.time = this.time % this.last_interval;
this.trigger( "on_tick", this.properties.event );

View File

@@ -98,6 +98,8 @@ GraphicsImage.prototype.onAdded = function()
GraphicsImage.prototype.onDrawBackground = function(ctx)
{
if(this.flags.collapsed)
return;
if(this.img && this.size[0] > 5 && this.size[1] > 5)
ctx.drawImage(this.img, 0,0,this.size[0],this.size[1]);
}
@@ -244,7 +246,7 @@ LiteGraph.registerNodeType("color/palette", ColorPalette );
function ImageFrame()
{
this.addInput("","image");
this.addInput("","image,canvas");
this.size = [200,200];
}
@@ -255,7 +257,7 @@ ImageFrame.widgets = [{name:"resize",text:"Resize box",type:"button"},{name:"vie
ImageFrame.prototype.onDrawBackground = function(ctx)
{
if(this.frame)
if(this.frame && !this.flags.collapsed)
ctx.drawImage(this.frame, 0,0,this.size[0],this.size[1]);
}
@@ -298,86 +300,6 @@ LiteGraph.registerNodeType("graphics/frame", ImageFrame );
/*
LiteGraph.registerNodeType("visualization/graph", {
desc: "Shows a graph of the inputs",
inputs: [["",0],["",0],["",0],["",0]],
size: [200,200],
properties: {min:-1,max:1,bgColor:"#000"},
onDrawBackground: function(ctx)
{
var colors = ["#FFF","#FAA","#AFA","#AAF"];
if(this.properties.bgColor != null && this.properties.bgColor != "")
{
ctx.fillStyle="#000";
ctx.fillRect(2,2,this.size[0] - 4, this.size[1]-4);
}
if(this.data)
{
var min = this.properties["min"];
var max = this.properties["max"];
for(var i in this.data)
{
var data = this.data[i];
if(!data) continue;
if(this.getInputInfo(i) == null) continue;
ctx.strokeStyle = colors[i];
ctx.beginPath();
var d = data.length / this.size[0];
for(var j = 0; j < data.length; j += d)
{
var value = data[ Math.floor(j) ];
value = (value - min) / (max - min);
if (value > 1.0) value = 1.0;
else if(value < 0) value = 0;
if(j == 0)
ctx.moveTo( j / d, (this.size[1] - 5) - (this.size[1] - 10) * value);
else
ctx.lineTo( j / d, (this.size[1] - 5) - (this.size[1] - 10) * value);
}
ctx.stroke();
}
}
//ctx.restore();
},
onExecute: function()
{
if(!this.data) this.data = [];
for(var i in this.inputs)
{
var value = this.getInputData(i);
if(typeof(value) == "number")
{
value = value ? value : 0;
if(!this.data[i])
this.data[i] = [];
this.data[i].push(value);
if(this.data[i].length > (this.size[1] - 4))
this.data[i] = this.data[i].slice(1,this.data[i].length);
}
else
this.data[i] = value;
}
if(this.data.length)
this.setDirtyCanvas(true);
}
});
*/
function ImageFade()
{
@@ -509,6 +431,105 @@ ImageCrop.prototype.onPropertyChanged = function(name,value)
LiteGraph.registerNodeType("graphics/cropImage", ImageCrop );
//CANVAS stuff
function CanvasNode()
{
this.addInput("clear", LiteGraph.ACTION );
this.addOutput("","canvas");
this.properties = {width:512,height:512,autoclear:true};
this.canvas = document.createElement("canvas");
this.ctx = this.canvas.getContext("2d");
}
CanvasNode.title = "Canvas";
CanvasNode.desc = "Canvas to render stuff";
CanvasNode.prototype.onExecute = function()
{
var canvas = this.canvas;
var w = (this.properties.width)|0;
var h = (this.properties.height)|0;
if( canvas.width != w )
canvas.width = w;
if( canvas.height != h )
canvas.height = h;
if(this.properties.autoclear)
this.ctx.clearRect(0,0,canvas.width,canvas.height);
this.setOutputData(0,canvas);
}
CanvasNode.prototype.onAction = function( action, param )
{
if(action == "clear")
this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);
}
LiteGraph.registerNodeType("graphics/canvas", CanvasNode );
function DrawImageNode()
{
this.addInput("canvas", "canvas" );
this.addInput("img", "image,canvas" );
this.addInput("x", "number" );
this.addInput("y", "number" );
this.properties = {x:0,y:0,opacity:1};
}
DrawImageNode.title = "DrawImage";
DrawImageNode.desc = "Draws image into a canvas";
DrawImageNode.prototype.onExecute = function()
{
var canvas = this.getInputData(0);
if(!canvas)
return;
var img = this.getInputOrProperty("img");
if(!img)
return;
var x = this.getInputOrProperty("x");
var y = this.getInputOrProperty("y");
var ctx = canvas.getContext("2d");
ctx.drawImage( img, x, y );
}
LiteGraph.registerNodeType("graphics/drawImage", DrawImageNode );
function DrawRectangleNode()
{
this.addInput("canvas", "canvas" );
this.addInput("x", "number" );
this.addInput("y", "number" );
this.addInput("w", "number" );
this.addInput("h", "number" );
this.properties = { x:0,y:0,w:10,h:10,color:"white",opacity:1 };
}
DrawRectangleNode.title = "DrawRectangle";
DrawRectangleNode.desc = "Draws rectangle in canvas";
DrawRectangleNode.prototype.onExecute = function()
{
var canvas = this.getInputData(0);
if(!canvas)
return;
var x = this.getInputOrProperty("x");
var y = this.getInputOrProperty("y");
var w = this.getInputOrProperty("w");
var h = this.getInputOrProperty("h");
var ctx = canvas.getContext("2d");
ctx.fillRect( x, y, w, h );
}
LiteGraph.registerNodeType("graphics/drawRectangle", DrawRectangleNode );
function ImageVideo()
{

View File

@@ -3,39 +3,92 @@ var LiteGraph = global.LiteGraph;
function Selector()
{
this.addInput("sel","boolean");
this.addOutput("value","number");
this.properties = { A:0, B:1 };
this.size = [60,20];
this.addInput("sel","number");
this.addInput("A");
this.addInput("B");
this.addInput("C");
this.addInput("D");
this.addOutput("out");
this.selected = 0;
}
Selector.title = "Selector";
Selector.desc = "outputs A if selector is true, B if selector is false";
Selector.desc = "selects an output";
Selector.prototype.onDrawBackground = function(ctx)
{
if(this.flags.collapsed)
return;
ctx.fillStyle = "#AFB";
var y = (this.selected + 1) * LiteGraph.NODE_SLOT_HEIGHT + 2;
ctx.beginPath();
ctx.moveTo(30, y);
ctx.lineTo(30, y+LiteGraph.NODE_SLOT_HEIGHT);
ctx.lineTo(24, y+LiteGraph.NODE_SLOT_HEIGHT*0.5);
ctx.fill();
}
Selector.prototype.onExecute = function()
{
var cond = this.getInputData(0);
if(cond === undefined)
return;
for(var i = 1; i < this.inputs.length; i++)
{
var input = this.inputs[i];
var v = this.getInputData(i);
if(v === undefined)
continue;
this.properties[input.name] = v;
}
var A = this.properties.A;
var B = this.properties.B;
this.setOutputData(0, cond ? A : B );
var sel = this.getInputData(0);
if(sel == null)
sel = 0;
this.selected = sel = Math.round(sel) % (this.inputs.length - 1);
var v = this.getInputData(sel + 1);
if(v !== undefined)
this.setOutputData( 0, v );
}
Selector.prototype.onGetInputs = function() {
return [["A",0],["B",0]];
return [["E",0],["F",0],["G",0],["H",0]];
}
LiteGraph.registerNodeType("logic/selector", Selector);
function Sequence()
{
this.properties = {
sequence: "A,B,C"
};
this.addInput("index","number");
this.addInput("seq");
this.addOutput("out");
this.index = 0;
this.values = this.properties.sequence.split(",");
}
Sequence.title = "Sequence";
Sequence.desc = "select one element from a sequence from a string";
Sequence.prototype.onPropertyChanged = function(name,value)
{
if(name == "sequence")
{
this.values = value.split(",");
}
}
Sequence.prototype.onExecute = function()
{
var seq = this.getInputData(1);
if(seq && seq != this.current_sequence)
{
this.values = seq.split(",");
this.current_sequence = seq;
}
var index = this.getInputData(0);
if(index == null)
index = 0;
this.index = index = Math.round(index) % this.values.length;
this.setOutputData( 0, this.values[ index ] );
}
LiteGraph.registerNodeType("logic/sequence", Sequence );
})(this);

View File

@@ -81,6 +81,23 @@ Bypass.prototype.onExecute = function()
LiteGraph.registerNodeType("math/bypass", Bypass );
function ToNumber()
{
this.addInput("in");
this.addOutput("out");
}
ToNumber.title = "to Number";
ToNumber.desc = "Cast to number";
ToNumber.prototype.onExecute = function()
{
var v = this.getInputData(0);
this.setOutputData(0, Number(v) );
}
LiteGraph.registerNodeType("math/to_number", ToNumber );
function MathRange()
{

View File

@@ -6,16 +6,17 @@ function MIDIEvent( data )
{
this.channel = 0;
this.cmd = 0;
this.data = new Uint32Array(3);
if(data)
this.setup(data)
else
this.data = [0,0,0];
}
LiteGraph.MIDIEvent = MIDIEvent;
MIDIEvent.prototype.setup = function( raw_data )
{
this.data = raw_data;
this.data.set(raw_data);
var midiStatus = raw_data[0];
this.status = midiStatus;
@@ -50,6 +51,32 @@ Object.defineProperty( MIDIEvent.prototype, "velocity", {
});
MIDIEvent.notes = ["A","A#","B","C","C#","D","D#","E","F","F#","G","G#"];
MIDIEvent.note_to_index = {"A":0,"A#":1,"B":2,"C":3,"C#":4,"D":5,"D#":6,"E":7,"F":8,"F#":9,"G":10,"G#":11};
Object.defineProperty( MIDIEvent.prototype, "note", {
get: function() {
if(this.cmd != MIDIEvent.NOTEON)
return -1;
return MIDIEvent.toNoteString( this.data[1], true );
},
set: function(v) {
throw("notes cannot be assigned this way, must modify the data[1]");
},
enumerable: true
});
Object.defineProperty( MIDIEvent.prototype, "octave", {
get: function() {
if(this.cmd != MIDIEvent.NOTEON)
return -1;
var octave = this.data[1] - 24;
return Math.floor(octave / 12 + 1);
},
set: function(v) {
throw("octave cannot be assigned this way, must modify the data[1]");
},
enumerable: true
});
//returns HZs
MIDIEvent.prototype.getPitch = function()
@@ -121,14 +148,39 @@ MIDIEvent.computeCommandFromString = function( str )
}
}
MIDIEvent.toNoteString = function(d)
//transform from a pitch number to string like "C4"
MIDIEvent.toNoteString = function( d, skip_octave )
{
d = Math.round(d); //in case it has decimals
var note = d - 21;
var octave = d - 24;
var octave = Math.floor((d - 24) / 12 + 1);
note = note % 12;
if(note < 0)
note = 12 + note;
return MIDIEvent.notes[ note ] + Math.floor(octave / 12 + 1);
return MIDIEvent.notes[ note ] + (skip_octave ? "" : octave);
}
MIDIEvent.NoteStringToPitch = function(str)
{
str = str.toUpperCase();
var note = str[0];
var octave = 4;
if(str[1] == "#")
{
note += "#";
if( str.length > 2 )
octave = Number( str[2] );
}
else
{
if( str.length > 1 )
octave = Number( str[1] );
}
var pitch = MIDIEvent.note_to_index[note];
if(pitch == null)
return null;
return ((octave - 1) * 12) + pitch + 21;
}
MIDIEvent.prototype.toString = function()
@@ -482,7 +534,7 @@ LGMIDIOut.prototype.getPropertyInfo = function(name)
LGMIDIOut.prototype.onAction = function(event, midi_event )
{
console.log(midi_event);
//console.log(midi_event);
if(!this._midi)
return;
if(event == "send")
@@ -581,7 +633,7 @@ function LGMIDIEvent()
{
this.properties = {
channel: 0,
cmd: "CC",
cmd: 144, //0x90
value1: 1,
value2: 1
};
@@ -589,6 +641,8 @@ function LGMIDIEvent()
this.addInput( "send", LiteGraph.EVENT );
this.addInput( "assign", LiteGraph.EVENT );
this.addOutput( "on_midi", LiteGraph.EVENT );
this.midi_event = new MIDIEvent();
}
LGMIDIEvent.title = "MIDIEvent";
@@ -606,7 +660,7 @@ LGMIDIEvent.prototype.onAction = function( event, midi_event )
}
//send
var midi_event = new MIDIEvent();
var midi_event = this.midi_event;
midi_event.channel = this.properties.channel;
if(this.properties.cmd && this.properties.cmd.constructor === String)
midi_event.setCommandFromString( this.properties.cmd );
@@ -615,6 +669,7 @@ LGMIDIEvent.prototype.onAction = function( event, midi_event )
midi_event.data[0] = midi_event.cmd | midi_event.channel;
midi_event.data[1] = Number(this.properties.value1);
midi_event.data[2] = Number(this.properties.value2);
this.trigger("on_midi",midi_event);
}
@@ -622,6 +677,28 @@ LGMIDIEvent.prototype.onExecute = function()
{
var props = this.properties;
if(this.inputs)
{
for(var i = 0; i < this.inputs.length; ++i)
{
var input = this.inputs[i];
if(input.link == -1)
continue;
switch (input.name)
{
case "note":
var v = this.getInputData(i);
if(v != null)
{
if(v.constructor === String)
v = MIDIEvent.NoteStringToPitch(v);
this.properties.value1 = (v|0)%255;
}
break;
}
}
}
if(this.outputs)
{
for(var i = 0; i < this.outputs.length; ++i)
@@ -657,6 +734,9 @@ LGMIDIEvent.prototype.onPropertyChanged = function(name,value)
this.properties.cmd = MIDIEvent.computeCommandFromString( value );
}
LGMIDIEvent.prototype.onGetInputs = function() {
return [ ["note","number"] ];
}
LGMIDIEvent.prototype.onGetOutputs = function() {
return [
@@ -701,6 +781,232 @@ LGMIDICC.prototype.onExecute = function()
LiteGraph.registerNodeType("midi/cc", LGMIDICC);
function LGMIDIGenerator()
{
this.addInput( "generate", LiteGraph.ACTION );
this.addInput( "scale", "string" );
this.addInput( "octave", "number" );
this.addOutput( "note", LiteGraph.EVENT );
this.properties = {
notes: "A,A#,B,C,C#,D,D#,E,F,F#,G,G#",
octave: 2,
mode: "sequence"
};
this.notes_pitches = LGMIDIGenerator.processScale( this.properties.notes );
this.sequence_index = 0;
}
LGMIDIGenerator.title = "MIDI Generator";
LGMIDIGenerator.desc = "Generates a random MIDI note";
LGMIDIGenerator.processScale = function(scale)
{
var notes = scale.split(",");
for(var i = 0; i < notes.length; ++i)
notes[i] = MIDIEvent.note_to_index[ notes[i] ] || 0;
return notes;
}
LGMIDIGenerator.prototype.onPropertyChanged = function(name,value)
{
if(name == "notes")
this.notes_pitches = LGMIDIGenerator.processScale( value );
}
LGMIDIGenerator.prototype.onExecute = function()
{
var octave = this.getInputData(2);
if(octave != null)
this.properties.octave = octave;
var scale = this.getInputData(1);
if(scale)
this.notes_pitches = LGMIDIGenerator.processScale( scale );
}
LGMIDIGenerator.prototype.onAction = function( event, midi_event )
{
//var range = this.properties.max - this.properties.min;
//var pitch = this.properties.min + ((Math.random() * range)|0);
var pitch = 0;
var range = this.notes_pitches.length;
if( this.properties.mode == "sequence" )
{
var index = this.sequence_index = (this.sequence_index + 1) % range;
pitch = this.notes_pitches[ index ] + ( (this.properties.octave-1) * 12) + 33;
}
else if( this.properties.mode == "random" )
{
var index = Math.floor(Math.random()*range);
pitch = this.notes_pitches[ index ] + ( (this.properties.octave-1) * 12) + 33;
}
var note = new MIDIEvent();
note.setup([ MIDIEvent.NOTEON, pitch, 10 ]);
this.trigger("note", note);
}
LiteGraph.registerNodeType("midi/generator", LGMIDIGenerator);
function LGMIDITranspose()
{
this.properties = {
amount: 0
};
this.addInput( "in", LiteGraph.ACTION );
this.addInput( "amount", "number" );
this.addOutput( "out", LiteGraph.EVENT );
this.midi_event = new MIDIEvent();
}
LGMIDITranspose.title = "MIDI Transpose";
LGMIDITranspose.desc = "Transpose a MIDI note";
LGMIDITranspose.prototype.onAction = function( event, midi_event )
{
this.midi_event.setup( midi_event.data );
this.midi_event.data[1] = Math.round( this.midi_event.data[1] + this.properties.amount );
this.trigger("out", this.midi_event );
}
LGMIDITranspose.prototype.onExecute = function()
{
var amount = this.getInputData(1);
if(amount!= null)
this.properties.amount = amount;
}
LiteGraph.registerNodeType("midi/transpose", LGMIDITranspose);
function LGMIDIQuantize()
{
this.properties = {
scale: "A,A#,B,C,C#,D,D#,E,F,F#,G,G#"
};
this.addInput( "note", LiteGraph.ACTION );
this.addInput( "scale", "string" );
this.addOutput( "out", LiteGraph.EVENT );
this.valid_notes = new Array(12);
this.offset_notes = new Array(12);
this.processScale( this.properties.scale );
this.midi_event = new MIDIEvent();
}
LGMIDIQuantize.title = "MIDI Quantize Pitch";
LGMIDIQuantize.desc = "Transpose a MIDI note tp fit an scale";
LGMIDIQuantize.prototype.onPropertyChanged = function(name,value)
{
if(name == "scale")
this.processScale( value );
}
LGMIDIQuantize.prototype.processScale = function( scale )
{
this._current_scale = scale;
this.notes_pitches = LGMIDIGenerator.processScale( scale );
for(var i = 0; i < 12; ++i)
this.valid_notes[i] = this.notes_pitches.indexOf(i) != -1;
for(var i = 0; i < 12; ++i)
{
if (this.valid_notes[ i ])
{
this.offset_notes[i] = 0;
continue;
}
for(var j = 1; j < 12; ++j)
{
if( this.valid_notes[ (i - j)%12 ] )
{
this.offset_notes[i] = -j;
break;
}
if( this.valid_notes[ (i + j)%12 ] )
{
this.offset_notes[i] = j;
break;
}
}
}
}
LGMIDIQuantize.prototype.onAction = function( event, midi_event )
{
this.midi_event.setup( midi_event.data );
var note = midi_event.note;
var index = MIDIEvent.note_to_index[ note ];
var offset = this.offset_notes[index];
this.midi_event.data[1] += offset;
this.trigger("out", this.midi_event );
}
LGMIDIQuantize.prototype.onExecute = function()
{
var scale = this.getInputData(1);
if(scale != null && scale != this._current_scale )
this.processScale( scale );
}
LiteGraph.registerNodeType("midi/quantize", LGMIDIQuantize);
function LGMIDIPlay()
{
this.properties = {
volume: 0.5,
duration: 1
};
this.addInput( "note", LiteGraph.ACTION );
this.addInput( "volume", "number" );
this.addInput( "duration", "number" );
this.addOutput( "note", LiteGraph.EVENT );
if(typeof(AudioSynth) == "undefined")
{
console.error("Audiosynth.js not included, LGMidiPlay requires that library");
this.boxcolor = "red";
}
else
{
var Synth = this.synth = new AudioSynth();
this.instrument = Synth.createInstrument('piano');
}
}
LGMIDIPlay.title = "MIDI Play";
LGMIDIPlay.desc = "Plays a MIDI note";
LGMIDIPlay.prototype.onAction = function( event, midi_event )
{
if(!this.instrument)
return;
var note = midi_event.note; //C#
if( !note || note == "undefined" || note.constructor !== String )
return;
this.instrument.play( note, midi_event.octave, this.properties.duration, this.properties.volume );
this.trigger("note", midi_event );
}
LGMIDIPlay.prototype.onExecute = function()
{
var volume = this.getInputData(1);
if(volume != null)
this.properties.volume = volume;
var duration = this.getInputData(2);
if(duration != null)
this.properties.duration = duration;
}
LiteGraph.registerNodeType("midi/play", LGMIDIPlay);
function now() { return window.performance.now() }