mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-05 05:00:03 +00:00
fixes
This commit is contained in:
770
src/litegraph.js
770
src/litegraph.js
File diff suppressed because it is too large
Load Diff
@@ -150,11 +150,11 @@ function GlobalInput()
|
||||
|
||||
this.addOutput(input_name, null );
|
||||
|
||||
this.properties = {name: input_name, type: null };
|
||||
this.properties = { name: input_name, type: null };
|
||||
|
||||
var that = this;
|
||||
|
||||
Object.defineProperty(this.properties, "name", {
|
||||
Object.defineProperty( this.properties, "name", {
|
||||
get: function() {
|
||||
return input_name;
|
||||
},
|
||||
@@ -173,7 +173,7 @@ function GlobalInput()
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
Object.defineProperty(this.properties, "type", {
|
||||
Object.defineProperty( this.properties, "type", {
|
||||
get: function() { return that.outputs[0].type; },
|
||||
set: function(v) {
|
||||
that.outputs[0].type = v;
|
||||
@@ -272,7 +272,7 @@ LiteGraph.registerNodeType("graph/output", GlobalOutput);
|
||||
function Constant()
|
||||
{
|
||||
this.addOutput("value","number");
|
||||
this.properties = { value:1.0 };
|
||||
this.addProperty( "value", 1.0 );
|
||||
this.editable = { property:"value", type:"number" };
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ function Watch()
|
||||
this.size = [60,20];
|
||||
this.addInput("value",0,{label:""});
|
||||
this.addOutput("value",0,{label:""});
|
||||
this.properties = { value:"" };
|
||||
this.addProperty( "value", "" );
|
||||
}
|
||||
|
||||
Watch.title = "Watch";
|
||||
@@ -348,16 +348,37 @@ LiteGraph.registerNodeType("basic/watch", Watch);
|
||||
//Show value inside the debug console
|
||||
function Console()
|
||||
{
|
||||
this.mode = LiteGraph.ON_EVENT;
|
||||
this.size = [60,20];
|
||||
this.addInput("data",0);
|
||||
this.addProperty( "msg", "" );
|
||||
this.addInput("log", LiteGraph.EVENT);
|
||||
this.addInput("msg",0);
|
||||
}
|
||||
|
||||
Console.title = "Console";
|
||||
Console.desc = "Show value inside the console";
|
||||
|
||||
Console.prototype.onAction = function(action, param)
|
||||
{
|
||||
if(action == "log")
|
||||
console.log( param );
|
||||
else if(action == "warn")
|
||||
console.warn( param );
|
||||
else if(action == "error")
|
||||
console.error( param );
|
||||
}
|
||||
|
||||
Console.prototype.onExecute = function()
|
||||
{
|
||||
console.log( this.getInputData(0) );
|
||||
var msg = this.getInputData(0);
|
||||
if(msg !== null)
|
||||
this.properties.msg = msg;
|
||||
console.log(msg);
|
||||
}
|
||||
|
||||
Console.prototype.onGetInputs = function()
|
||||
{
|
||||
return [["log",LiteGraph.ACTION],["warn",LiteGraph.ACTION],["error",LiteGraph.ACTION]];
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("basic/console", Console );
|
||||
|
||||
51
src/nodes/events.js
Normal file
51
src/nodes/events.js
Normal file
@@ -0,0 +1,51 @@
|
||||
//event related nodes
|
||||
(function(){
|
||||
|
||||
//Show value inside the debug console
|
||||
function DelayEvent()
|
||||
{
|
||||
this.size = [60,20];
|
||||
this.addProperty( "time", 1000 );
|
||||
this.addInput("event", LiteGraph.ACTION);
|
||||
this.addOutput("on_time", LiteGraph.EVENT);
|
||||
|
||||
this._pending = [];
|
||||
}
|
||||
|
||||
DelayEvent.title = "Delay";
|
||||
DelayEvent.desc = "Delays one event";
|
||||
|
||||
DelayEvent.prototype.onAction = function(action, param)
|
||||
{
|
||||
this._pending.push([ this.properties.time, param ]);
|
||||
}
|
||||
|
||||
DelayEvent.prototype.onExecute = function()
|
||||
{
|
||||
var dt = this.graph.elapsed_time * 1000; //in ms
|
||||
|
||||
for(var i = 0; i < this._pending.length; ++i)
|
||||
{
|
||||
var action = this._pending[i];
|
||||
action[0] -= dt;
|
||||
if( action[0] > 0 )
|
||||
continue;
|
||||
|
||||
//remove
|
||||
this._pending.splice(i,1);
|
||||
--i;
|
||||
|
||||
//trigger
|
||||
this.trigger(null, action[1]);
|
||||
}
|
||||
}
|
||||
|
||||
DelayEvent.prototype.onGetInputs = function()
|
||||
{
|
||||
return [["event",LiteGraph.ACTION]];
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("events/delay", DelayEvent );
|
||||
|
||||
|
||||
})();
|
||||
@@ -309,6 +309,9 @@ if(typeof(LiteGraph) != "undefined")
|
||||
if(this.flags.collapsed)
|
||||
return;
|
||||
|
||||
if(!ctx.webgl)
|
||||
return; //not working well
|
||||
|
||||
var tex = this.getInputData(0);
|
||||
if(!tex) return;
|
||||
|
||||
@@ -833,7 +836,7 @@ if(typeof(LiteGraph) != "undefined")
|
||||
function LGraphTextureToViewport()
|
||||
{
|
||||
this.addInput("Texture","Texture");
|
||||
this.properties = { additive: false, antialiasing: false, disable_alpha: false, gamma: 1.0 };
|
||||
this.properties = { additive: false, antialiasing: false, filter: true, disable_alpha: false, gamma: 1.0 };
|
||||
this.size[0] = 130;
|
||||
}
|
||||
|
||||
@@ -862,6 +865,7 @@ if(typeof(LiteGraph) != "undefined")
|
||||
if( this.isInputConnected(1) )
|
||||
gamma = this.getInputData(1);
|
||||
|
||||
tex.setParameter( gl.TEXTURE_MAG_FILTER, this.properties.filter ? gl.LINEAR : gl.NEAREST );
|
||||
|
||||
if(this.properties.antialiasing)
|
||||
{
|
||||
@@ -1774,38 +1778,23 @@ if(typeof(LiteGraph) != "undefined")
|
||||
this.properties.intensity = intensity;
|
||||
}
|
||||
|
||||
gl.disable( gl.BLEND );
|
||||
gl.disable( gl.DEPTH_TEST );
|
||||
var mesh = Mesh.getScreenQuad();
|
||||
var shader = LGraphTextureBlur._shader;
|
||||
var scale = this.properties.scale || [1,1];
|
||||
|
||||
//blur sometimes needs an aspect correction
|
||||
var aspect = LiteGraph.camera_aspect;
|
||||
if(!aspect && window.gl !== undefined)
|
||||
aspect = gl.canvas.height / gl.canvas.width;
|
||||
if(!aspect)
|
||||
aspect = 1;
|
||||
|
||||
//iterate
|
||||
var start_texture = tex;
|
||||
aspect = this.properties.preserve_aspect ? aspect : 1;
|
||||
|
||||
var start_texture = tex;
|
||||
var scale = this.properties.scale || [1,1];
|
||||
var origin = start_texture;
|
||||
for(var i = 0; i < iterations; ++i)
|
||||
{
|
||||
this._temp_texture.drawTo( function() {
|
||||
start_texture.bind(0);
|
||||
shader.uniforms({u_texture:0, u_intensity: 1, u_offset: [0, 1/start_texture.height * scale[1] ] })
|
||||
.draw(mesh);
|
||||
});
|
||||
|
||||
this._temp_texture.bind(0);
|
||||
this._final_texture.drawTo( function() {
|
||||
shader.uniforms({u_texture:0, u_intensity: intensity, u_offset: [aspect/start_texture.width * scale[0], 0] })
|
||||
.draw(mesh);
|
||||
});
|
||||
start_texture = this._final_texture;
|
||||
origin.applyBlur( aspect * scale[0] * i, scale[1] * i, intensity, this._temp_texture, this._final_texture );
|
||||
origin = this._final_texture;
|
||||
}
|
||||
|
||||
|
||||
this.setOutputData(0, this._final_texture);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,65 @@
|
||||
//widgets
|
||||
(function(){
|
||||
|
||||
/* Button ****************/
|
||||
|
||||
function WidgetButton()
|
||||
{
|
||||
this.addOutput( "clicked", LiteGraph.EVENT );
|
||||
this.addProperty( "text","" );
|
||||
this.addProperty( "font","40px Arial" );
|
||||
this.addProperty( "message", "" );
|
||||
this.size = [64,84];
|
||||
}
|
||||
|
||||
WidgetButton.title = "Button";
|
||||
WidgetButton.desc = "Triggers an event";
|
||||
|
||||
WidgetButton.prototype.onDrawForeground = function(ctx)
|
||||
{
|
||||
if(this.flags.collapsed)
|
||||
return;
|
||||
|
||||
//ctx.font = "40px Arial";
|
||||
//ctx.textAlign = "center";
|
||||
ctx.fillStyle = "black";
|
||||
ctx.fillRect(1,1,this.size[0] - 3, this.size[1] - 3);
|
||||
ctx.fillStyle = "#AAF";
|
||||
ctx.fillRect(0,0,this.size[0] - 3, this.size[1] - 3);
|
||||
ctx.fillStyle = this.clicked ? "white" : (this.mouseOver ? "#668" : "#334");
|
||||
ctx.fillRect(1,1,this.size[0] - 4, this.size[1] - 4);
|
||||
|
||||
if( this.properties.text || this.properties.text === 0 )
|
||||
{
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillStyle = this.clicked ? "black" : "white";
|
||||
if( this.properties.font )
|
||||
ctx.font = this.properties.font;
|
||||
ctx.fillText(this.properties.text, this.size[0] * 0.5, this.size[1] * 0.85 );
|
||||
ctx.textAlign = "left";
|
||||
}
|
||||
}
|
||||
|
||||
WidgetButton.prototype.onMouseDown = function(e, local_pos)
|
||||
{
|
||||
if(local_pos[0] > 1 && local_pos[1] > 1 && local_pos[0] < (this.size[0] - 2) && local_pos[1] < (this.size[1] - 2) )
|
||||
{
|
||||
this.clicked = true;
|
||||
this.trigger( "clicked", this.properties.message );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
WidgetButton.prototype.onMouseUp = function(e)
|
||||
{
|
||||
this.clicked = false;
|
||||
}
|
||||
|
||||
|
||||
LiteGraph.registerNodeType("widget/button", WidgetButton );
|
||||
|
||||
/* Knob ****************/
|
||||
|
||||
function WidgetKnob()
|
||||
{
|
||||
this.addOutput("",'number');
|
||||
|
||||
@@ -85,7 +85,12 @@ function MathRange()
|
||||
{
|
||||
this.addInput("in","number",{locked:true});
|
||||
this.addOutput("out","number",{locked:true});
|
||||
this.properties = { "in": 0, in_min:0, in_max:1, out_min: 0, out_max: 1 };
|
||||
|
||||
this.addProperty( "in", 0 );
|
||||
this.addProperty( "in_min", 0 );
|
||||
this.addProperty( "in_max", 1 );
|
||||
this.addProperty( "out_min", 0 );
|
||||
this.addProperty( "out_max", 1 );
|
||||
}
|
||||
|
||||
MathRange.title = "Range";
|
||||
@@ -136,7 +141,8 @@ LiteGraph.registerNodeType("math/range", MathRange);
|
||||
function MathRand()
|
||||
{
|
||||
this.addOutput("value","number");
|
||||
this.properties = { min:0, max:1 };
|
||||
this.addProperty( "min", 0 );
|
||||
this.addProperty( "max", 1 );
|
||||
this.size = [60,20];
|
||||
}
|
||||
|
||||
@@ -182,7 +188,8 @@ function MathClamp()
|
||||
this.addInput("in","number");
|
||||
this.addOutput("out","number");
|
||||
this.size = [60,20];
|
||||
this.properties = {min:0, max:1};
|
||||
this.addProperty( "min", 0 );
|
||||
this.addProperty( "max", 1 );
|
||||
}
|
||||
|
||||
MathClamp.title = "Clamp";
|
||||
@@ -310,7 +317,7 @@ function MathScale()
|
||||
this.addInput("in","number",{label:""});
|
||||
this.addOutput("out","number",{label:""});
|
||||
this.size = [60,20];
|
||||
this.properties = {"factor":1};
|
||||
this.addProperty( "factor", 1 );
|
||||
}
|
||||
|
||||
MathScale.title = "Scale";
|
||||
@@ -326,18 +333,73 @@ MathScale.prototype.onExecute = function()
|
||||
LiteGraph.registerNodeType("math/scale", MathScale );
|
||||
|
||||
|
||||
//Math clamp
|
||||
function MathAverageFilter()
|
||||
{
|
||||
this.addInput("in","number");
|
||||
this.addOutput("out","number");
|
||||
this.size = [60,20];
|
||||
this.addProperty( "samples", 10 );
|
||||
this._values = new Float32Array(10);
|
||||
this._current = 0;
|
||||
}
|
||||
|
||||
MathAverageFilter.title = "Average";
|
||||
MathAverageFilter.desc = "Average Filter";
|
||||
|
||||
MathAverageFilter.prototype.onExecute = function()
|
||||
{
|
||||
var v = this.getInputData(0);
|
||||
if(v == null)
|
||||
v = 0;
|
||||
|
||||
var num_samples = this._values.length;
|
||||
|
||||
this._values[ this._current % num_samples ] = v;
|
||||
this._current += 1;
|
||||
if(this._current > num_samples)
|
||||
this._current = 0;
|
||||
|
||||
var avr = 0;
|
||||
for(var i = 0; i < num_samples; ++i)
|
||||
avr += this._values[i];
|
||||
|
||||
this.setOutputData( 0, avr / num_samples );
|
||||
}
|
||||
|
||||
MathAverageFilter.prototype.onPropertyChanged = function( name, value )
|
||||
{
|
||||
if(value < 1)
|
||||
value = 1;
|
||||
this.properties.samples = Math.round(value);
|
||||
var old = this._values;
|
||||
|
||||
this._values = new Float32Array( this.properties.samples );
|
||||
if(old.length <= this._values.length )
|
||||
this._values.set(old);
|
||||
else
|
||||
this._values.set( old.subarray( 0, this._values.length ) );
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("math/average", MathAverageFilter );
|
||||
|
||||
|
||||
//Math operation
|
||||
function MathOperation()
|
||||
{
|
||||
this.addInput("A","number");
|
||||
this.addInput("B","number");
|
||||
this.addOutput("=","number");
|
||||
this.properties = {A:1.0, B:1.0, OP:"+"};
|
||||
this.addProperty( "A", 1 );
|
||||
this.addProperty( "B", 1 );
|
||||
this.addProperty( "OP", "+", "string", { values: MathOperation.values } );
|
||||
}
|
||||
|
||||
MathOperation.values = ["+","-","*","/","%","^"];
|
||||
|
||||
MathOperation.title = "Operation";
|
||||
MathOperation.desc = "Easy math operators";
|
||||
MathOperation["@OP"] = { type:"enum", title: "operation", values:["+","-","*","/","%","^"]};
|
||||
MathOperation["@OP"] = { type:"enum", title: "operation", values: MathOperation.values };
|
||||
|
||||
|
||||
MathOperation.prototype.setValue = function(v)
|
||||
@@ -365,16 +427,28 @@ MathOperation.prototype.onExecute = function()
|
||||
{
|
||||
case '+': result = A+B; break;
|
||||
case '-': result = A-B; break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
case '*': result = A*B; break;
|
||||
case '/': result = A/B; break;
|
||||
case '%': result = A%B; break;
|
||||
case '^': result = Math.pow(A,B); break;
|
||||
default:
|
||||
console.warn("Unknown operation: " + this.properties.OP);
|
||||
}
|
||||
this.setOutputData(0, result );
|
||||
}
|
||||
|
||||
MathOperation.prototype.onDrawBackground = function(ctx)
|
||||
{
|
||||
this.outputs[0].label = "A" + this.properties.OP + "B";
|
||||
if(this.flags.collapsed)
|
||||
return;
|
||||
|
||||
ctx.font = "40px Arial";
|
||||
ctx.fillStyle = "black";
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText(this.properties.OP, this.size[0] * 0.5, this.size[1] * 0.5 + LiteGraph.NODE_TITLE_HEIGHT );
|
||||
ctx.textAlign = "left";
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("math/operation", MathOperation );
|
||||
@@ -387,7 +461,8 @@ function MathCompare()
|
||||
this.addInput( "B","number" );
|
||||
this.addOutput("A==B","boolean");
|
||||
this.addOutput("A!=B","boolean");
|
||||
this.properties = {A:0,B:0};
|
||||
this.addProperty( "A", 0 );
|
||||
this.addProperty( "B", 0 );
|
||||
}
|
||||
|
||||
MathCompare.title = "Compare";
|
||||
@@ -437,11 +512,15 @@ function MathCondition()
|
||||
this.addInput("A","number");
|
||||
this.addInput("B","number");
|
||||
this.addOutput("out","boolean");
|
||||
this.properties = { A:0, B:1, OP:">" };
|
||||
this.addProperty( "A", 1 );
|
||||
this.addProperty( "B", 1 );
|
||||
this.addProperty( "OP", ">", "string", { values: MathCondition.values } );
|
||||
|
||||
this.size = [60,40];
|
||||
}
|
||||
|
||||
MathCondition["@OP"] = { type:"enum", title: "operation", values:[">","<","==","!=","<=",">="]};
|
||||
MathCondition.values = [">","<","==","!=","<=",">="];
|
||||
MathCondition["@OP"] = { type:"enum", title: "operation", values: MathCondition.values };
|
||||
|
||||
MathCondition.title = "Condition";
|
||||
MathCondition.desc = "evaluates condition between A and B";
|
||||
@@ -481,7 +560,8 @@ function MathAccumulate()
|
||||
{
|
||||
this.addInput("inc","number");
|
||||
this.addOutput("total","number");
|
||||
this.properties = { increment: 0, value: 0 };
|
||||
this.addProperty( "increment", 1 );
|
||||
this.addProperty( "value", 0 );
|
||||
}
|
||||
|
||||
MathAccumulate.title = "Accumulate";
|
||||
@@ -489,6 +569,9 @@ MathAccumulate.desc = "Increments a value every time";
|
||||
|
||||
MathAccumulate.prototype.onExecute = function()
|
||||
{
|
||||
if(this.properties.value === null)
|
||||
this.properties.value = 0;
|
||||
|
||||
var inc = this.getInputData(0);
|
||||
if(inc !== null)
|
||||
this.properties.value += inc;
|
||||
@@ -504,7 +587,9 @@ function MathTrigonometry()
|
||||
{
|
||||
this.addInput("v","number");
|
||||
this.addOutput("sin","number");
|
||||
this.properties = {amplitude:1.0, offset: 0};
|
||||
|
||||
this.addProperty( "amplitude", 1 );
|
||||
this.addProperty( "offset", 0 );
|
||||
this.bgImageUrl = "nodes/imgs/icon-sin.png";
|
||||
}
|
||||
|
||||
@@ -515,6 +600,8 @@ MathTrigonometry.filter = "shader";
|
||||
MathTrigonometry.prototype.onExecute = function()
|
||||
{
|
||||
var v = this.getInputData(0);
|
||||
if(v == null)
|
||||
v = 0;
|
||||
var amplitude = this.properties["amplitude"];
|
||||
var slot = this.findInputSlot("amplitude");
|
||||
if(slot != -1)
|
||||
@@ -778,12 +865,35 @@ LiteGraph.registerNodeType("math3d/xyzw-to-vec4", Math3DXYZWToVec4 );
|
||||
if(window.glMatrix)
|
||||
{
|
||||
|
||||
function Math3DQuaternion()
|
||||
{
|
||||
this.addOutput("quat","quat");
|
||||
this.properties = { x:0, y:0, z:0, w: 1 };
|
||||
this._value = quat.create();
|
||||
}
|
||||
|
||||
Math3DQuaternion.title = "Quaternion";
|
||||
Math3DQuaternion.desc = "quaternion";
|
||||
|
||||
Math3DQuaternion.prototype.onExecute = function()
|
||||
{
|
||||
this._value[0] = this.properties.x;
|
||||
this._value[1] = this.properties.y;
|
||||
this._value[2] = this.properties.z;
|
||||
this._value[3] = this.properties.w;
|
||||
this.setOutputData( 0, this._value );
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("math3d/quaternion", Math3DQuaternion );
|
||||
|
||||
|
||||
function Math3DRotation()
|
||||
{
|
||||
this.addInputs([["degrees","number"],["axis","vec3"]]);
|
||||
this.addOutput("quat","quat");
|
||||
this.properties = { angle:90.0, axis: vec3.fromValues(0,1,0) };
|
||||
|
||||
this._value = quat.create();
|
||||
}
|
||||
|
||||
Math3DRotation.title = "Rotation";
|
||||
@@ -796,7 +906,7 @@ if(window.glMatrix)
|
||||
var axis = this.getInputData(1);
|
||||
if(axis == null) axis = this.properties.axis;
|
||||
|
||||
var R = quat.setAxisAngle(quat.create(), axis, angle * 0.0174532925 );
|
||||
var R = quat.setAxisAngle( this._value, axis, angle * 0.0174532925 );
|
||||
this.setOutputData( 0, R );
|
||||
}
|
||||
|
||||
@@ -834,6 +944,8 @@ if(window.glMatrix)
|
||||
{
|
||||
this.addInputs( [["A","quat"],["B","quat"]] );
|
||||
this.addOutput( "A*B","quat" );
|
||||
|
||||
this._value = quat.create();
|
||||
}
|
||||
|
||||
Math3DMultQuat.title = "Mult. Quat";
|
||||
@@ -846,12 +958,43 @@ if(window.glMatrix)
|
||||
var B = this.getInputData(1);
|
||||
if(B == null) return;
|
||||
|
||||
var R = quat.multiply(quat.create(), A,B);
|
||||
var R = quat.multiply( this._value, A, B );
|
||||
this.setOutputData( 0, R );
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("math3d/mult-quat", Math3DMultQuat );
|
||||
|
||||
|
||||
function Math3DQuatSlerp()
|
||||
{
|
||||
this.addInputs( [["A","quat"],["B","quat"],["factor","number"]] );
|
||||
this.addOutput( "slerp","quat" );
|
||||
this.addProperty( "factor", 0.5 );
|
||||
|
||||
this._value = quat.create();
|
||||
}
|
||||
|
||||
Math3DQuatSlerp.title = "Quat Slerp";
|
||||
Math3DQuatSlerp.desc = "quaternion spherical interpolation";
|
||||
|
||||
Math3DQuatSlerp.prototype.onExecute = function()
|
||||
{
|
||||
var A = this.getInputData(0);
|
||||
if(A == null)
|
||||
return;
|
||||
var B = this.getInputData(1);
|
||||
if(B == null)
|
||||
return;
|
||||
var factor = this.properties.factor;
|
||||
if( this.getInputData(2) != null )
|
||||
factor = this.getInputData(2);
|
||||
|
||||
var R = quat.slerp( this._value, A, B, factor );
|
||||
this.setOutputData( 0, R );
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("math3d/quat-slerp", Math3DQuatSlerp );
|
||||
|
||||
} //glMatrix
|
||||
|
||||
})();
|
||||
614
src/nodes/midi.js
Normal file
614
src/nodes/midi.js
Normal file
@@ -0,0 +1,614 @@
|
||||
(function( global )
|
||||
{
|
||||
|
||||
function MIDIEvent( data )
|
||||
{
|
||||
this.channel = 0;
|
||||
this.cmd = 0;
|
||||
|
||||
if(data)
|
||||
this.setup(data)
|
||||
else
|
||||
this.data = [0,0,0];
|
||||
}
|
||||
|
||||
MIDIEvent.prototype.setup = function( raw_data )
|
||||
{
|
||||
this.data = raw_data;
|
||||
|
||||
var midiStatus = raw_data[0];
|
||||
this.status = midiStatus;
|
||||
|
||||
var midiCommand = midiStatus & 0xF0;
|
||||
|
||||
if(midiStatus >= 0xF0)
|
||||
this.cmd = midiStatus;
|
||||
else
|
||||
this.cmd = midiCommand;
|
||||
|
||||
if(this.cmd == MIDIEvent.NOTEON && this.velocity == 0)
|
||||
this.cmd = MIDIEvent.NOTEOFF;
|
||||
|
||||
this.cmd_str = MIDIEvent.commands[ this.cmd ] || "";
|
||||
|
||||
if ( midiCommand >= MIDIEvent.NOTEON || midiCommand <= MIDIEvent.NOTEOFF ) {
|
||||
this.channel = midiStatus & 0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty( MIDIEvent.prototype, "velocity", {
|
||||
get: function() {
|
||||
if(this.cmd == MIDIEvent.NOTEON)
|
||||
return this.data[2];
|
||||
return -1;
|
||||
},
|
||||
set: function(v) {
|
||||
this.data[2] = v; // v / 127;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
MIDIEvent.notes = ["A","A#","B","C","C#","D","D#","E","F","F#","G","G#"];
|
||||
|
||||
//returns HZs
|
||||
MIDIEvent.prototype.getPitch = function()
|
||||
{
|
||||
return Math.pow(2, (this.data[1] - 69) / 12 ) * 440;
|
||||
}
|
||||
|
||||
MIDIEvent.computePitch = function( note )
|
||||
{
|
||||
return Math.pow(2, (note - 69) / 12 ) * 440;
|
||||
}
|
||||
|
||||
|
||||
//not tested, there is a formula missing here
|
||||
MIDIEvent.prototype.getPitchBend = function()
|
||||
{
|
||||
return this.data[1] + (this.data[2] << 7) - 8192;
|
||||
}
|
||||
|
||||
MIDIEvent.computePitchBend = function(v1,v2)
|
||||
{
|
||||
return v1 + (v2 << 7) - 8192;
|
||||
}
|
||||
|
||||
MIDIEvent.prototype.setCommandFromString = function( str )
|
||||
{
|
||||
this.cmd = MIDIEvent.computeCommandFromString(str);
|
||||
}
|
||||
|
||||
MIDIEvent.computeCommandFromString = function( str )
|
||||
{
|
||||
if(!str)
|
||||
return 0;
|
||||
|
||||
if(str && str.constructor === Number)
|
||||
return str;
|
||||
|
||||
str = str.toUpperCase();
|
||||
switch( str )
|
||||
{
|
||||
case "NOTE ON":
|
||||
case "NOTEON": return MIDIEvent.NOTEON; break;
|
||||
case "NOTE OFF":
|
||||
case "NOTEOFF": return MIDIEvent.NOTEON; break;
|
||||
case "KEY PRESSURE":
|
||||
case "KEYPRESSURE": return MIDIEvent.KEYPRESSURE; break;
|
||||
case "CONTROLLER CHANGE":
|
||||
case "CONTROLLERCHANGE":
|
||||
case "CC": return MIDIEvent.CONTROLLERCHANGE; break;
|
||||
case "PROGRAM CHANGE":
|
||||
case "PROGRAMCHANGE":
|
||||
case "PC": return MIDIEvent.PROGRAMCHANGE; break;
|
||||
case "CHANNEL PRESSURE":
|
||||
case "CHANNELPRESSURE": return MIDIEvent.CHANNELPRESSURE; break;
|
||||
case "PITCH BEND":
|
||||
case "PITCHBEND": return MIDIEvent.PITCHBEND; break;
|
||||
case "TIME TICK":
|
||||
case "TIMETICK": return MIDIEvent.TIMETICK; break;
|
||||
default: return Number(str); //asume its a hex code
|
||||
}
|
||||
}
|
||||
|
||||
MIDIEvent.toNoteString = function(d)
|
||||
{
|
||||
var note = d - 21;
|
||||
var octave = d - 24;
|
||||
note = note % 12;
|
||||
if(note < 0)
|
||||
note = 12 + note;
|
||||
return MIDIEvent.notes[ note ] + Math.floor(octave / 12 + 1);
|
||||
}
|
||||
|
||||
MIDIEvent.prototype.toString = function()
|
||||
{
|
||||
var str = "" + this.channel + ". " ;
|
||||
switch( this.cmd )
|
||||
{
|
||||
case MIDIEvent.NOTEON: str += "NOTEON " + MIDIEvent.toNoteString( this.data[1] ); break;
|
||||
case MIDIEvent.NOTEOFF: str += "NOTEOFF " + MIDIEvent.toNoteString( this.data[1] ); break;
|
||||
case MIDIEvent.CONTROLLERCHANGE: str += "CC " + this.data[1] + " " + this.data[2]; break;
|
||||
case MIDIEvent.PROGRAMCHANGE: str += "PC " + this.data[1]; break;
|
||||
case MIDIEvent.PITCHBEND: str += "PITCHBEND " + this.getPitchBend(); break;
|
||||
case MIDIEvent.KEYPRESSURE: str += "KEYPRESS " + this.data[1]; break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
MIDIEvent.prototype.toHexString = function()
|
||||
{
|
||||
var str = "";
|
||||
for(var i = 0; i < this.data.length; i++)
|
||||
str += this.data[i].toString(16) + " ";
|
||||
}
|
||||
|
||||
MIDIEvent.NOTEOFF = 0x80;
|
||||
MIDIEvent.NOTEON = 0x90;
|
||||
MIDIEvent.KEYPRESSURE = 0xA0;
|
||||
MIDIEvent.CONTROLLERCHANGE = 0xB0;
|
||||
MIDIEvent.PROGRAMCHANGE = 0xC0;
|
||||
MIDIEvent.CHANNELPRESSURE = 0xD0;
|
||||
MIDIEvent.PITCHBEND = 0xE0;
|
||||
MIDIEvent.TIMETICK = 0xF8;
|
||||
|
||||
MIDIEvent.commands = {
|
||||
0x80: "note off",
|
||||
0x90: "note on",
|
||||
0xA0: "key pressure",
|
||||
0xB0: "controller change",
|
||||
0xC0: "program change",
|
||||
0xD0: "channel pressure",
|
||||
0xE0: "pitch bend",
|
||||
0xF0: "system",
|
||||
0xF2: "Song pos",
|
||||
0xF3: "Song select",
|
||||
0xF6: "Tune request",
|
||||
0xF8: "time tick",
|
||||
0xFA: "Start Song",
|
||||
0xFB: "Continue Song",
|
||||
0xFC: "Stop Song",
|
||||
0xFE: "Sensing",
|
||||
0xFF: "Reset"
|
||||
}
|
||||
|
||||
//MIDI wrapper
|
||||
function MIDIInterface( on_ready, on_error )
|
||||
{
|
||||
if(!navigator.requestMIDIAccess)
|
||||
{
|
||||
this.error = "not suppoorted";
|
||||
if(on_error)
|
||||
on_error("Not supported");
|
||||
else
|
||||
console.error("MIDI NOT SUPPORTED, enable by chrome://flags");
|
||||
return;
|
||||
}
|
||||
|
||||
this.on_ready = on_ready;
|
||||
|
||||
navigator.requestMIDIAccess().then( this.onMIDISuccess.bind(this), this.onMIDIFailure.bind(this) );
|
||||
}
|
||||
|
||||
MIDIInterface.MIDIEvent = MIDIEvent;
|
||||
|
||||
MIDIInterface.prototype.onMIDISuccess = function(midiAccess)
|
||||
{
|
||||
console.log( "MIDI ready!" );
|
||||
console.log( midiAccess );
|
||||
this.midi = midiAccess; // store in the global (in real usage, would probably keep in an object instance)
|
||||
this.updatePorts();
|
||||
|
||||
if (this.on_ready)
|
||||
this.on_ready(this);
|
||||
}
|
||||
|
||||
MIDIInterface.prototype.updatePorts = function()
|
||||
{
|
||||
var midi = this.midi;
|
||||
this.input_ports = midi.inputs;
|
||||
var num = 0;
|
||||
for (var i = 0; i < this.input_ports.size; ++i) {
|
||||
var input = this.input_ports.get(i);
|
||||
console.log( "Input port [type:'" + input.type + "'] id:'" + input.id +
|
||||
"' manufacturer:'" + input.manufacturer + "' name:'" + input.name +
|
||||
"' version:'" + input.version + "'" );
|
||||
num++;
|
||||
}
|
||||
this.num_input_ports = num;
|
||||
|
||||
|
||||
num = 0;
|
||||
this.output_ports = midi.outputs;
|
||||
for (var i = 0; i < this.output_ports.size; ++i) {
|
||||
var output = this.output_ports.get(i);
|
||||
console.log( "Output port [type:'" + output.type + "'] id:'" + output.id +
|
||||
"' manufacturer:'" + output.manufacturer + "' name:'" + output.name +
|
||||
"' version:'" + output.version + "'" );
|
||||
num++;
|
||||
}
|
||||
this.num_output_ports = num;
|
||||
}
|
||||
|
||||
MIDIInterface.prototype.onMIDIFailure = function(msg)
|
||||
{
|
||||
console.error( "Failed to get MIDI access - " + msg );
|
||||
}
|
||||
|
||||
MIDIInterface.prototype.openInputPort = function( port, callback)
|
||||
{
|
||||
var input_port = this.input_ports.get( port );
|
||||
if(!input_port)
|
||||
return false;
|
||||
|
||||
input_port.onmidimessage = function(a) {
|
||||
var midi_event = new MIDIEvent(a.data);
|
||||
if(callback)
|
||||
callback(a.data, midi_event );
|
||||
if(MIDIInterface.on_message)
|
||||
MIDIInterface.on_message( a.data, midi_event );
|
||||
}
|
||||
console.log("port open: ", input_port);
|
||||
return true;
|
||||
}
|
||||
|
||||
MIDIInterface.parseMsg = function(data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
MIDIInterface.prototype.sendMIDI = function( port, midi_data )
|
||||
{
|
||||
if( !midi_data )
|
||||
return;
|
||||
|
||||
var output_port = this.output_ports.get(port);
|
||||
if(!output_port)
|
||||
return;
|
||||
|
||||
if( midi_data.constructor === MIDIEvent)
|
||||
output_port.send( midi_data.data );
|
||||
else
|
||||
output_port.send( midi_data );
|
||||
}
|
||||
|
||||
|
||||
|
||||
function LGMIDIIn()
|
||||
{
|
||||
this.addOutput( "on_midi", LiteGraph.EVENT );
|
||||
this.addOutput( "out", "midi" );
|
||||
this.properties = {port: 0};
|
||||
this._last_midi_event = null;
|
||||
this._current_midi_event = null;
|
||||
|
||||
var that = this;
|
||||
new MIDIInterface( function( midi ){
|
||||
//open
|
||||
that._midi = midi;
|
||||
if(that._waiting)
|
||||
that.onStart();
|
||||
that._waiting = false;
|
||||
});
|
||||
}
|
||||
|
||||
LGMIDIIn.MIDIInterface = MIDIInterface;
|
||||
|
||||
LGMIDIIn.title = "MIDI Input";
|
||||
LGMIDIIn.desc = "Reads MIDI from a input port";
|
||||
|
||||
LGMIDIIn.prototype.getPropertyInfo = function(name)
|
||||
{
|
||||
if(!this._midi)
|
||||
return;
|
||||
|
||||
if(name == "port")
|
||||
{
|
||||
var values = {};
|
||||
for (var i = 0; i < this._midi.input_ports.size; ++i)
|
||||
{
|
||||
var input = this._midi.input_ports.get(i);
|
||||
values[i] = i + ".- " + input.name + " version:" + input.version;
|
||||
}
|
||||
return { type: "enum", values: values };
|
||||
}
|
||||
}
|
||||
|
||||
LGMIDIIn.prototype.onStart = function()
|
||||
{
|
||||
if(this._midi)
|
||||
this._midi.openInputPort( this.properties.port, this.onMIDIEvent.bind(this) );
|
||||
else
|
||||
this._waiting = true;
|
||||
}
|
||||
|
||||
LGMIDIIn.prototype.onMIDIEvent = function( data, midi_event )
|
||||
{
|
||||
this._last_midi_event = midi_event;
|
||||
|
||||
this.trigger( "on_midi", midi_event );
|
||||
if(midi_event.cmd == MIDIEvent.NOTEON)
|
||||
this.trigger( "on_noteon", midi_event );
|
||||
else if(midi_event.cmd == MIDIEvent.NOTEOFF)
|
||||
this.trigger( "on_noteoff", midi_event );
|
||||
else if(midi_event.cmd == MIDIEvent.CONTROLLERCHANGE)
|
||||
this.trigger( "on_cc", midi_event );
|
||||
else if(midi_event.cmd == MIDIEvent.PROGRAMCHANGE)
|
||||
this.trigger( "on_pc", midi_event );
|
||||
else if(midi_event.cmd == MIDIEvent.PITCHBEND)
|
||||
this.trigger( "on_pitchbend", midi_event );
|
||||
}
|
||||
|
||||
LGMIDIIn.prototype.onExecute = function()
|
||||
{
|
||||
if(this.outputs)
|
||||
{
|
||||
var last = this._last_midi_event;
|
||||
for(var i = 0; i < this.outputs.length; ++i)
|
||||
{
|
||||
var output = this.outputs[i];
|
||||
var v = null;
|
||||
switch (output.name)
|
||||
{
|
||||
case "last_midi": v = last; break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
this.setOutputData( i, v );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LGMIDIIn.prototype.onGetOutputs = function() {
|
||||
return [
|
||||
["last_midi","midi"],
|
||||
["on_midi",LiteGraph.EVENT],
|
||||
["on_noteon",LiteGraph.EVENT],
|
||||
["on_noteoff",LiteGraph.EVENT],
|
||||
["on_cc",LiteGraph.EVENT],
|
||||
["on_pc",LiteGraph.EVENT],
|
||||
["on_pitchbend",LiteGraph.EVENT]
|
||||
];
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("midi/input", LGMIDIIn);
|
||||
|
||||
|
||||
function LGMIDIOut()
|
||||
{
|
||||
this.addInput( "send", LiteGraph.EVENT );
|
||||
this.properties = {port: 0};
|
||||
|
||||
var that = this;
|
||||
new MIDIInterface( function( midi ){
|
||||
that._midi = midi;
|
||||
});
|
||||
}
|
||||
|
||||
LGMIDIOut.MIDIInterface = MIDIInterface;
|
||||
|
||||
LGMIDIOut.title = "MIDI Output";
|
||||
LGMIDIOut.desc = "Sends MIDI to output channel";
|
||||
|
||||
LGMIDIOut.prototype.getPropertyInfo = function(name)
|
||||
{
|
||||
if(!this._midi)
|
||||
return;
|
||||
|
||||
if(name == "port")
|
||||
{
|
||||
var values = {};
|
||||
for (var i = 0; i < this._midi.output_ports.size; ++i)
|
||||
{
|
||||
var output = this._midi.output_ports.get(i);
|
||||
values[i] = i + ".- " + output.name + " version:" + output.version;
|
||||
}
|
||||
return { type: "enum", values: values };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LGMIDIOut.prototype.onAction = function(event, midi_event )
|
||||
{
|
||||
console.log(midi_event);
|
||||
if(!this._midi)
|
||||
return;
|
||||
if(event == "send")
|
||||
this._midi.sendMIDI( this.port, midi_event );
|
||||
this.trigger("midi",midi_event);
|
||||
}
|
||||
|
||||
LGMIDIOut.prototype.onGetInputs = function() {
|
||||
return [["send",LiteGraph.ACTION]];
|
||||
}
|
||||
|
||||
LGMIDIOut.prototype.onGetOutputs = function() {
|
||||
return [["on_midi",LiteGraph.EVENT]];
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("midi/output", LGMIDIOut);
|
||||
|
||||
|
||||
function LGMIDIShow()
|
||||
{
|
||||
this.addInput( "on_midi", LiteGraph.EVENT );
|
||||
this._str = "";
|
||||
this.size = [200,40]
|
||||
}
|
||||
|
||||
LGMIDIShow.title = "MIDI Show";
|
||||
LGMIDIShow.desc = "Shows MIDI in the graph";
|
||||
|
||||
LGMIDIShow.prototype.onAction = function(event, midi_event )
|
||||
{
|
||||
if(!midi_event)
|
||||
return;
|
||||
if(midi_event.constructor === MIDIEvent)
|
||||
this._str = midi_event.toString();
|
||||
else
|
||||
this._str = "???";
|
||||
}
|
||||
|
||||
LGMIDIShow.prototype.onDrawForeground = function( ctx )
|
||||
{
|
||||
if( !this._str )
|
||||
return;
|
||||
|
||||
ctx.font = "30px Arial";
|
||||
ctx.fillText( this._str, 10, this.size[1] * 0.8 );
|
||||
}
|
||||
|
||||
LGMIDIShow.prototype.onGetInputs = function() {
|
||||
return [["in",LiteGraph.ACTION]];
|
||||
}
|
||||
|
||||
LGMIDIShow.prototype.onGetOutputs = function() {
|
||||
return [["on_midi",LiteGraph.EVENT]];
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("midi/show", LGMIDIShow);
|
||||
|
||||
|
||||
|
||||
function LGMIDIFilter()
|
||||
{
|
||||
this.properties = {
|
||||
channel: -1,
|
||||
cmd: -1,
|
||||
min_value: -1,
|
||||
max_value: -1
|
||||
};
|
||||
|
||||
this.addInput( "in", LiteGraph.EVENT );
|
||||
this.addOutput( "on_midi", LiteGraph.EVENT );
|
||||
}
|
||||
|
||||
LGMIDIFilter.title = "MIDI Filter";
|
||||
LGMIDIFilter.desc = "Filters MIDI messages";
|
||||
|
||||
LGMIDIFilter.prototype.onAction = function(event, midi_event )
|
||||
{
|
||||
if(!midi_event || midi_event.constructor !== MIDIEvent)
|
||||
return;
|
||||
|
||||
if( this.properties.channel != -1 && midi_event.channel != this.properties.channel)
|
||||
return;
|
||||
if(this.properties.cmd != -1 && midi_event.cmd != this.properties.cmd)
|
||||
return;
|
||||
if(this.properties.min_value != -1 && midi_event.data[1] < this.properties.min_value)
|
||||
return;
|
||||
if(this.properties.max_value != -1 && midi_event.data[1] > this.properties.max_value)
|
||||
return;
|
||||
this.trigger("on_midi",midi_event);
|
||||
}
|
||||
|
||||
LiteGraph.registerNodeType("midi/filter", LGMIDIFilter);
|
||||
|
||||
|
||||
function LGMIDIEvent()
|
||||
{
|
||||
this.properties = {
|
||||
channel: 0,
|
||||
cmd: "CC",
|
||||
value1: 1,
|
||||
value2: 1
|
||||
};
|
||||
|
||||
this.addInput( "send", LiteGraph.EVENT );
|
||||
this.addInput( "assign", LiteGraph.EVENT );
|
||||
this.addOutput( "on_midi", LiteGraph.EVENT );
|
||||
}
|
||||
|
||||
LGMIDIEvent.title = "MIDIEvent";
|
||||
LGMIDIEvent.desc = "Create a MIDI Event";
|
||||
|
||||
LGMIDIEvent.prototype.onAction = function( event, midi_event )
|
||||
{
|
||||
if(event == "assign")
|
||||
{
|
||||
this.properties.channel = midi_event.channel;
|
||||
this.properties.cmd = midi_event.cmd;
|
||||
this.properties.value1 = midi_event.data[1];
|
||||
this.properties.value2 = midi_event.data[2];
|
||||
return;
|
||||
}
|
||||
|
||||
//send
|
||||
var midi_event = new MIDIEvent();
|
||||
midi_event.channel = this.properties.channel;
|
||||
if(this.properties.cmd && this.properties.cmd.constructor === String)
|
||||
midi_event.setCommandFromString( this.properties.cmd );
|
||||
else
|
||||
midi_event.cmd = this.properties.cmd;
|
||||
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);
|
||||
}
|
||||
|
||||
LGMIDIEvent.prototype.onExecute = function()
|
||||
{
|
||||
var props = this.properties;
|
||||
|
||||
if(this.outputs)
|
||||
{
|
||||
for(var i = 0; i < this.outputs.length; ++i)
|
||||
{
|
||||
var output = this.outputs[i];
|
||||
var v = null;
|
||||
switch (output.name)
|
||||
{
|
||||
case "midi":
|
||||
v = new MIDIEvent();
|
||||
v.setup([ props.cmd, props.value1, props.value2 ]);
|
||||
v.channel = props.channel;
|
||||
break;
|
||||
case "command": v = props.cmd; break;
|
||||
case "note": v = (props.cmd == MIDIEvent.NOTEON || props.cmd == MIDIEvent.NOTEOFF) ? props.value1 : NULL; break;
|
||||
case "velocity": v = props.cmd == MIDIEvent.NOTEON ? props.value2 : NULL; break;
|
||||
case "pitch": v = props.cmd == MIDIEvent.NOTEON ? MIDIEvent.computePitch( props.value1 ) : null; break;
|
||||
case "pitchbend": v = props.cmd == MIDIEvent.PITCHBEND ? MIDIEvent.computePitchBend( props.value1, props.value2 ) : null; break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
if(v !== null)
|
||||
this.setOutputData( i, v );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LGMIDIEvent.prototype.onPropertyChanged = function(name,value)
|
||||
{
|
||||
if(name == "cmd")
|
||||
this.properties.cmd = MIDIEvent.computeCommandFromString( value );
|
||||
}
|
||||
|
||||
|
||||
LGMIDIEvent.prototype.onGetOutputs = function() {
|
||||
return [
|
||||
["midi","midi"],
|
||||
["on_midi",LiteGraph.EVENT],
|
||||
["command","number"],
|
||||
["note","number"],
|
||||
["velocity","number"],
|
||||
["pitch","number"],
|
||||
["pitchbend","number"]
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
LiteGraph.registerNodeType("midi/event", LGMIDIEvent);
|
||||
|
||||
|
||||
|
||||
|
||||
function now() { return window.performance.now() }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
})( window );
|
||||
Reference in New Issue
Block a user