mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-02 22:37:32 +00:00
extended MIDI support. Some new general purpose nodes like sequencer, string, cast to number.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
1011
build/litegraph.min.js
vendored
1011
build/litegraph.min.js
vendored
File diff suppressed because it is too large
Load Diff
1
demo/examples/midi_generation.json
Normal file
1
demo/examples/midi_generation.json
Normal file
File diff suppressed because one or more lines are too long
@@ -15,15 +15,17 @@
|
||||
|
||||
<script type="text/javascript" src="../external/jquery-1.6.2.min.js"></script>
|
||||
<script type="text/javascript" src="http://tamats.com/projects/sillyserver/src/sillyclient.js"></script>
|
||||
<script type="text/javascript" src="js/libs/audiosynth.js"></script>
|
||||
|
||||
<script type="text/javascript" src="../src/litegraph.js"></script>
|
||||
<script type="text/javascript" src="../src/litegraph-editor.js"></script>
|
||||
|
||||
<script type="text/javascript" src="../src/nodes/base.js"></script>
|
||||
<script type="text/javascript" src="../src/nodes/logic.js"></script>
|
||||
<script type="text/javascript" src="../src/nodes/events.js"></script>
|
||||
<script type="text/javascript" src="../src/nodes/math.js"></script>
|
||||
<script type="text/javascript" src="../src/nodes/interface.js"></script>
|
||||
<script type="text/javascript" src="../src/nodes/image.js"></script>
|
||||
<script type="text/javascript" src="../src/nodes/graphics.js"></script>
|
||||
<script type="text/javascript" src="../src/nodes/input.js"></script>
|
||||
<script type="text/javascript" src="../src/nodes/midi.js"></script>
|
||||
<script type="text/javascript" src="../src/nodes/audio.js"></script>
|
||||
|
||||
@@ -5,6 +5,10 @@ window.graphcanvas = editor.graphcanvas;
|
||||
window.graph = editor.graph;
|
||||
window.addEventListener("resize", function() { editor.graphcanvas.resize(); } );
|
||||
window.addEventListener("keydown", editor.graphcanvas.processKey.bind(editor.graphcanvas) );
|
||||
window.onbeforeunload = function(){
|
||||
var data = JSON.stringify( graph.serialize() );
|
||||
localStorage.setItem("litegraphg demo backup", data );
|
||||
}
|
||||
|
||||
//create scene selector
|
||||
var elem = document.createElement("span");
|
||||
@@ -18,6 +22,8 @@ select.addEventListener("change", function(e){
|
||||
|
||||
if(url)
|
||||
graph.load( url );
|
||||
else if(option.callback)
|
||||
option.callback();
|
||||
else
|
||||
graph.clear();
|
||||
});
|
||||
@@ -37,7 +43,10 @@ elem.querySelector("#load").addEventListener("click",function(){
|
||||
function addDemo( name, url )
|
||||
{
|
||||
var option = document.createElement("option");
|
||||
option.dataset["url"] = url;
|
||||
if(url.constructor === String)
|
||||
option.dataset["url"] = url;
|
||||
else
|
||||
option.callback = url;
|
||||
option.innerHTML = name;
|
||||
select.appendChild( option );
|
||||
}
|
||||
@@ -48,6 +57,14 @@ addDemo("Benchmark", "examples/benchmark.json");
|
||||
addDemo("Audio", "examples/audio.json");
|
||||
addDemo("Audio Delay", "examples/audio_delay.json");
|
||||
addDemo("Audio Reverb", "examples/audio_reverb.json");
|
||||
addDemo("MIDI Generation", "examples/midi_generation.json");
|
||||
addDemo("autobackup", function(){
|
||||
var data = localStorage.getItem("litegraphg demo backup");
|
||||
if(!data)
|
||||
return;
|
||||
var graph_data = JSON.parse(data);
|
||||
graph.configure( graph_data );
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ function TestSlotsNode()
|
||||
this.addInput("C","number");
|
||||
this.addOutput("A","number");
|
||||
this.addOutput("B","number");
|
||||
this.flags = { horizontal: true };
|
||||
this.horizontal = true;
|
||||
this.size = [100,40];
|
||||
}
|
||||
|
||||
|
||||
356
demo/js/libs/audiosynth.js
Normal file
356
demo/js/libs/audiosynth.js
Normal file
@@ -0,0 +1,356 @@
|
||||
var Synth, AudioSynth, AudioSynthInstrument;
|
||||
!function(){
|
||||
|
||||
var URL = window.URL || window.webkitURL;
|
||||
var Blob = window.Blob;
|
||||
|
||||
if(!URL || !Blob) {
|
||||
throw new Error('This browser does not support AudioSynth');
|
||||
}
|
||||
|
||||
var _encapsulated = false;
|
||||
var AudioSynthInstance = null;
|
||||
var pack = function(c,arg){ return [new Uint8Array([arg, arg >> 8]), new Uint8Array([arg, arg >> 8, arg >> 16, arg >> 24])][c]; };
|
||||
var setPrivateVar = function(n,v,w,e){Object.defineProperty(this,n,{value:v,writable:!!w,enumerable:!!e});};
|
||||
var setPublicVar = function(n,v,w){setPrivateVar.call(this,n,v,w,true);};
|
||||
AudioSynthInstrument = function AudioSynthInstrument(){this.__init__.apply(this,arguments);};
|
||||
var setPriv = setPrivateVar.bind(AudioSynthInstrument.prototype);
|
||||
var setPub = setPublicVar.bind(AudioSynthInstrument.prototype);
|
||||
setPriv('__init__', function(a,b,c) {
|
||||
if(!_encapsulated) { throw new Error('AudioSynthInstrument can only be instantiated from the createInstrument method of the AudioSynth object.'); }
|
||||
setPrivateVar.call(this, '_parent', a);
|
||||
setPublicVar.call(this, 'name', b);
|
||||
setPrivateVar.call(this, '_soundID', c);
|
||||
});
|
||||
setPub('play', function(note, octave, duration,volume) {
|
||||
return this._parent.play(this._soundID, note, octave, duration, volume);
|
||||
});
|
||||
setPub('generate', function(note, octave, duration) {
|
||||
return this._parent.generate(this._soundID, note, octave, duration);
|
||||
});
|
||||
AudioSynth = function AudioSynth(){if(AudioSynthInstance instanceof AudioSynth){return AudioSynthInstance;}else{ this.__init__(); return this; }};
|
||||
setPriv = setPrivateVar.bind(AudioSynth.prototype);
|
||||
setPub = setPublicVar.bind(AudioSynth.prototype);
|
||||
setPriv('_debug',false,true);
|
||||
setPriv('_bitsPerSample',16);
|
||||
setPriv('_channels',1);
|
||||
setPriv('_sampleRate',44100,true);
|
||||
setPub('setSampleRate', function(v) {
|
||||
this._sampleRate = Math.max(Math.min(v|0,44100), 4000);
|
||||
this._clearCache();
|
||||
return this._sampleRate;
|
||||
});
|
||||
setPub('getSampleRate', function() { return this._sampleRate; });
|
||||
setPriv('_volume',32768,true);
|
||||
setPub('setVolume', function(v) {
|
||||
v = parseFloat(v); if(isNaN(v)) { v = 0; }
|
||||
v = Math.round(v*32768);
|
||||
this._volume = Math.max(Math.min(v|0,32768), 0);
|
||||
this._clearCache();
|
||||
return this._volume;
|
||||
});
|
||||
setPub('getVolume', function() { return Math.round(this._volume/32768*10000)/10000; });
|
||||
setPriv('_notes',{'C':261.63,'C#':277.18,'D':293.66,'D#':311.13,'E':329.63,'F':346.23,'F#':369.99,'G':392.00,'G#':415.30,'A':440.00,'A#':466.16,'B':493.88});
|
||||
setPriv('_fileCache',[],true);
|
||||
setPriv('_temp',{},true);
|
||||
setPriv('_sounds',[],true);
|
||||
setPriv('_mod',[function(i,s,f,x){return Math.sin((2 * Math.PI)*(i/s)*f+x);}]);
|
||||
setPriv('_resizeCache', function() {
|
||||
var f = this._fileCache;
|
||||
var l = this._sounds.length;
|
||||
while(f.length<l) {
|
||||
var octaveList = [];
|
||||
for(var i = 0; i < 8; i++) {
|
||||
var noteList = {};
|
||||
for(var k in this._notes) {
|
||||
noteList[k] = {};
|
||||
}
|
||||
octaveList.push(noteList);
|
||||
}
|
||||
f.push(octaveList);
|
||||
}
|
||||
});
|
||||
setPriv('_clearCache', function() {
|
||||
this._fileCache = [];
|
||||
this._resizeCache();
|
||||
});
|
||||
setPub('generate', function(sound, note, octave, duration) {
|
||||
var thisSound = this._sounds[sound];
|
||||
if(!thisSound) {
|
||||
for(var i=0;i<this._sounds.length;i++) {
|
||||
if(this._sounds[i].name==sound) {
|
||||
thisSound = this._sounds[i];
|
||||
sound = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!thisSound) { throw new Error('Invalid sound or sound ID: ' + sound); }
|
||||
var t = (new Date).valueOf();
|
||||
this._temp = {};
|
||||
octave |= 0;
|
||||
octave = Math.min(8, Math.max(1, octave));
|
||||
var time = !duration?2:parseFloat(duration);
|
||||
if(typeof(this._notes[note])=='undefined') { throw new Error(note + ' is not a valid note.'); }
|
||||
if(typeof(this._fileCache[sound][octave-1][note][time])!='undefined') {
|
||||
if(this._debug) { console.log((new Date).valueOf() - t, 'ms to retrieve (cached)'); }
|
||||
return this._fileCache[sound][octave-1][note][time];
|
||||
} else {
|
||||
var frequency = this._notes[note] * Math.pow(2,octave-4);
|
||||
var sampleRate = this._sampleRate;
|
||||
var volume = this._volume;
|
||||
var channels = this._channels;
|
||||
var bitsPerSample = this._bitsPerSample;
|
||||
var attack = thisSound.attack(sampleRate, frequency, volume);
|
||||
var dampen = thisSound.dampen(sampleRate, frequency, volume);
|
||||
var waveFunc = thisSound.wave;
|
||||
var waveBind = {modulate: this._mod, vars: this._temp};
|
||||
var val = 0;
|
||||
var curVol = 0;
|
||||
|
||||
var data = new Uint8Array(new ArrayBuffer(Math.ceil(sampleRate * time * 2)));
|
||||
var attackLen = (sampleRate * attack) | 0;
|
||||
var decayLen = (sampleRate * time) | 0;
|
||||
|
||||
for (var i = 0 | 0; i !== attackLen; i++) {
|
||||
|
||||
val = volume * (i/(sampleRate*attack)) * waveFunc.call(waveBind, i, sampleRate, frequency, volume);
|
||||
|
||||
data[i << 1] = val;
|
||||
data[(i << 1) + 1] = val >> 8;
|
||||
|
||||
}
|
||||
|
||||
for (; i !== decayLen; i++) {
|
||||
|
||||
val = volume * Math.pow((1-((i-(sampleRate*attack))/(sampleRate*(time-attack)))),dampen) * waveFunc.call(waveBind, i, sampleRate, frequency, volume);
|
||||
|
||||
data[i << 1] = val;
|
||||
data[(i << 1) + 1] = val >> 8;
|
||||
|
||||
}
|
||||
|
||||
var out = [
|
||||
'RIFF',
|
||||
pack(1, 4 + (8 + 24/* chunk 1 length */) + (8 + 8/* chunk 2 length */)), // Length
|
||||
'WAVE',
|
||||
// chunk 1
|
||||
'fmt ', // Sub-chunk identifier
|
||||
pack(1, 16), // Chunk length
|
||||
pack(0, 1), // Audio format (1 is linear quantization)
|
||||
pack(0, channels),
|
||||
pack(1, sampleRate),
|
||||
pack(1, sampleRate * channels * bitsPerSample / 8), // Byte rate
|
||||
pack(0, channels * bitsPerSample / 8),
|
||||
pack(0, bitsPerSample),
|
||||
// chunk 2
|
||||
'data', // Sub-chunk identifier
|
||||
pack(1, data.length * channels * bitsPerSample / 8), // Chunk length
|
||||
data
|
||||
];
|
||||
var blob = new Blob(out, {type: 'audio/wav'});
|
||||
var dataURI = URL.createObjectURL(blob);
|
||||
this._fileCache[sound][octave-1][note][time] = dataURI;
|
||||
if(this._debug) { console.log((new Date).valueOf() - t, 'ms to generate'); }
|
||||
return dataURI;
|
||||
}
|
||||
});
|
||||
setPub('play', function(sound, note, octave, duration, volume) {
|
||||
var src = this.generate( sound, note, octave, duration );
|
||||
var audio = new Audio(src);
|
||||
if(volume != null)
|
||||
{
|
||||
if(volume <= 0)
|
||||
return true;
|
||||
audio.volume = volume > 1 ? 1 : volume;
|
||||
}
|
||||
audio.play();
|
||||
return true;
|
||||
});
|
||||
setPub('debug', function() { this._debug = true; });
|
||||
setPub('createInstrument', function(sound) {
|
||||
var n = 0;
|
||||
var found = false;
|
||||
if(typeof(sound)=='string') {
|
||||
for(var i=0;i<this._sounds.length;i++) {
|
||||
if(this._sounds[i].name==sound) {
|
||||
found = true;
|
||||
n = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(this._sounds[sound]) {
|
||||
n = sound;
|
||||
sound = this._sounds[n].name;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if(!found) { throw new Error('Invalid sound or sound ID: ' + sound); }
|
||||
_encapsulated = true;
|
||||
var ins = new AudioSynthInstrument(this, sound, n);
|
||||
_encapsulated = false;
|
||||
return ins;
|
||||
});
|
||||
setPub('listSounds', function() {
|
||||
var r = [];
|
||||
for(var i=0;i<this._sounds.length;i++) {
|
||||
r.push(this._sounds[i].name);
|
||||
}
|
||||
return r;
|
||||
});
|
||||
setPriv('__init__', function(){
|
||||
this._resizeCache();
|
||||
});
|
||||
setPub('loadSoundProfile', function() {
|
||||
for(var i=0,len=arguments.length;i<len;i++) {
|
||||
o = arguments[i];
|
||||
if(!(o instanceof Object)) { throw new Error('Invalid sound profile.'); }
|
||||
this._sounds.push(o);
|
||||
}
|
||||
this._resizeCache();
|
||||
return true;
|
||||
});
|
||||
setPub('loadModulationFunction', function() {
|
||||
for(var i=0,len=arguments.length;i<len;i++) {
|
||||
f = arguments[i];
|
||||
if(typeof(f)!='function') { throw new Error('Invalid modulation function.'); }
|
||||
this._mod.push(f);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
AudioSynthInstance = new AudioSynth();
|
||||
Synth = AudioSynthInstance;
|
||||
}();
|
||||
|
||||
Synth.loadModulationFunction(
|
||||
function(i, sampleRate, frequency, x) { return 1 * Math.sin(2 * Math.PI * ((i / sampleRate) * frequency) + x); },
|
||||
function(i, sampleRate, frequency, x) { return 1 * Math.sin(4 * Math.PI * ((i / sampleRate) * frequency) + x); },
|
||||
function(i, sampleRate, frequency, x) { return 1 * Math.sin(8 * Math.PI * ((i / sampleRate) * frequency) + x); },
|
||||
function(i, sampleRate, frequency, x) { return 1 * Math.sin(0.5 * Math.PI * ((i / sampleRate) * frequency) + x); },
|
||||
function(i, sampleRate, frequency, x) { return 1 * Math.sin(0.25 * Math.PI * ((i / sampleRate) * frequency) + x); },
|
||||
function(i, sampleRate, frequency, x) { return 0.5 * Math.sin(2 * Math.PI * ((i / sampleRate) * frequency) + x); },
|
||||
function(i, sampleRate, frequency, x) { return 0.5 * Math.sin(4 * Math.PI * ((i / sampleRate) * frequency) + x); },
|
||||
function(i, sampleRate, frequency, x) { return 0.5 * Math.sin(8 * Math.PI * ((i / sampleRate) * frequency) + x); },
|
||||
function(i, sampleRate, frequency, x) { return 0.5 * Math.sin(0.5 * Math.PI * ((i / sampleRate) * frequency) + x); },
|
||||
function(i, sampleRate, frequency, x) { return 0.5 * Math.sin(0.25 * Math.PI * ((i / sampleRate) * frequency) + x); }
|
||||
);
|
||||
|
||||
Synth.loadSoundProfile({
|
||||
name: 'piano',
|
||||
attack: function() { return 0.002; },
|
||||
dampen: function(sampleRate, frequency, volume) {
|
||||
return Math.pow(0.5*Math.log((frequency*volume)/sampleRate),2);
|
||||
},
|
||||
wave: function(i, sampleRate, frequency, volume) {
|
||||
var base = this.modulate[0];
|
||||
return this.modulate[1](
|
||||
i,
|
||||
sampleRate,
|
||||
frequency,
|
||||
Math.pow(base(i, sampleRate, frequency, 0), 2) +
|
||||
(0.75 * base(i, sampleRate, frequency, 0.25)) +
|
||||
(0.1 * base(i, sampleRate, frequency, 0.5))
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'organ',
|
||||
attack: function() { return 0.3 },
|
||||
dampen: function(sampleRate, frequency) { return 1+(frequency * 0.01); },
|
||||
wave: function(i, sampleRate, frequency) {
|
||||
var base = this.modulate[0];
|
||||
return this.modulate[1](
|
||||
i,
|
||||
sampleRate,
|
||||
frequency,
|
||||
base(i, sampleRate, frequency, 0) +
|
||||
0.5*base(i, sampleRate, frequency, 0.25) +
|
||||
0.25*base(i, sampleRate, frequency, 0.5)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'acoustic',
|
||||
attack: function() { return 0.002; },
|
||||
dampen: function() { return 1; },
|
||||
wave: function(i, sampleRate, frequency) {
|
||||
|
||||
var vars = this.vars;
|
||||
vars.valueTable = !vars.valueTable?[]:vars.valueTable;
|
||||
if(typeof(vars.playVal)=='undefined') { vars.playVal = 0; }
|
||||
if(typeof(vars.periodCount)=='undefined') { vars.periodCount = 0; }
|
||||
|
||||
var valueTable = vars.valueTable;
|
||||
var playVal = vars.playVal;
|
||||
var periodCount = vars.periodCount;
|
||||
|
||||
var period = sampleRate/frequency;
|
||||
var p_hundredth = Math.floor((period-Math.floor(period))*100);
|
||||
|
||||
var resetPlay = false;
|
||||
|
||||
if(valueTable.length<=Math.ceil(period)) {
|
||||
|
||||
valueTable.push(Math.round(Math.random())*2-1);
|
||||
|
||||
return valueTable[valueTable.length-1];
|
||||
|
||||
} else {
|
||||
|
||||
valueTable[playVal] = (valueTable[playVal>=(valueTable.length-1)?0:playVal+1] + valueTable[playVal]) * 0.5;
|
||||
|
||||
if(playVal>=Math.floor(period)) {
|
||||
if(playVal<Math.ceil(period)) {
|
||||
if((periodCount%100)>=p_hundredth) {
|
||||
// Reset
|
||||
resetPlay = true;
|
||||
valueTable[playVal+1] = (valueTable[0] + valueTable[playVal+1]) * 0.5;
|
||||
vars.periodCount++;
|
||||
}
|
||||
} else {
|
||||
resetPlay = true;
|
||||
}
|
||||
}
|
||||
|
||||
var _return = valueTable[playVal];
|
||||
if(resetPlay) { vars.playVal = 0; } else { vars.playVal++; }
|
||||
|
||||
return _return;
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'edm',
|
||||
attack: function() { return 0.002; },
|
||||
dampen: function() { return 1; },
|
||||
wave: function(i, sampleRate, frequency) {
|
||||
var base = this.modulate[0];
|
||||
var mod = this.modulate.slice(1);
|
||||
return mod[0](
|
||||
i,
|
||||
sampleRate,
|
||||
frequency,
|
||||
mod[9](
|
||||
i,
|
||||
sampleRate,
|
||||
frequency,
|
||||
mod[2](
|
||||
i,
|
||||
sampleRate,
|
||||
frequency,
|
||||
Math.pow(base(i, sampleRate, frequency, 0), 3) +
|
||||
Math.pow(base(i, sampleRate, frequency, 0.5), 5) +
|
||||
Math.pow(base(i, sampleRate, frequency, 1), 7)
|
||||
)
|
||||
) +
|
||||
mod[8](
|
||||
i,
|
||||
sampleRate,
|
||||
frequency,
|
||||
base(i, sampleRate, frequency, 1.75)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "litegraph.js",
|
||||
"version": "0.6.0",
|
||||
"version": "0.7.0",
|
||||
"description": "A graph node editor similar to PD or UDK Blueprints, it works in a HTML5 Canvas and allow to exported graphs to be included in applications.",
|
||||
"main": "build/litegraph.js",
|
||||
"directories": {
|
||||
@@ -28,13 +28,13 @@
|
||||
},
|
||||
"homepage": "https://github.com/kriffe/litegraph.js#readme",
|
||||
"devDependencies": {
|
||||
"express": "^4.16.2",
|
||||
"express": "^4.16.4",
|
||||
"google-closure-compiler": "^20171112.0.0",
|
||||
"grunt": "^1.0.1",
|
||||
"grunt": "^1.0.3",
|
||||
"grunt-cli": "^1.2.0",
|
||||
"grunt-closure-tools": "^1.0.0",
|
||||
"grunt-contrib-concat": "^1.0.1",
|
||||
"nodemon": "^1.14.7",
|
||||
"nodemon": "^1.18.9",
|
||||
"rimraf": "^2.6.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
@@ -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);
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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() }
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
../src/nodes/input.js
|
||||
../src/nodes/math.js
|
||||
../src/nodes/logic.js
|
||||
../src/nodes/image.js
|
||||
../src/nodes/graphics.js
|
||||
../src/nodes/gltextures.js
|
||||
../src/nodes/glfx.js
|
||||
../src/nodes/midi.js
|
||||
|
||||
Reference in New Issue
Block a user