|
import { app } from "../../../scripts/app.js";
|
|
|
|
app.registerExtension({
|
|
name: "KJNodes.jsnodes",
|
|
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
|
if(!nodeData?.category?.startsWith("KJNodes")) {
|
|
return;
|
|
}
|
|
switch (nodeData.name) {
|
|
case "ConditioningMultiCombine":
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
this.cond_type = "CONDITIONING"
|
|
this.inputs_offset = nodeData.name.includes("selective")?1:0
|
|
this.addWidget("button", "Update inputs", null, () => {
|
|
if (!this.inputs) {
|
|
this.inputs = [];
|
|
}
|
|
const target_number_of_inputs = this.widgets.find(w => w.name === "inputcount")["value"];
|
|
if(target_number_of_inputs===this.inputs.length)return;
|
|
|
|
if(target_number_of_inputs < this.inputs.length){
|
|
for(let i = this.inputs.length; i>=this.inputs_offset+target_number_of_inputs; i--)
|
|
this.removeInput(i)
|
|
}
|
|
else{
|
|
for(let i = this.inputs.length+1-this.inputs_offset; i <= target_number_of_inputs; ++i)
|
|
this.addInput(`conditioning_${i}`, this.cond_type)
|
|
}
|
|
});
|
|
}
|
|
break;
|
|
case "ImageBatchMulti":
|
|
case "ImageAddMulti":
|
|
case "ImageConcatMulti":
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
this._type = "IMAGE"
|
|
this.inputs_offset = nodeData.name.includes("selective")?1:0
|
|
this.addWidget("button", "Update inputs", null, () => {
|
|
if (!this.inputs) {
|
|
this.inputs = [];
|
|
}
|
|
const target_number_of_inputs = this.widgets.find(w => w.name === "inputcount")["value"];
|
|
if(target_number_of_inputs===this.inputs.length)return;
|
|
|
|
if(target_number_of_inputs < this.inputs.length){
|
|
for(let i = this.inputs.length; i>=this.inputs_offset+target_number_of_inputs; i--)
|
|
this.removeInput(i)
|
|
}
|
|
else{
|
|
for(let i = this.inputs.length+1-this.inputs_offset; i <= target_number_of_inputs; ++i)
|
|
this.addInput(`image_${i}`, this._type)
|
|
}
|
|
});
|
|
}
|
|
break;
|
|
case "MaskBatchMulti":
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
this._type = "MASK"
|
|
this.inputs_offset = nodeData.name.includes("selective")?1:0
|
|
this.addWidget("button", "Update inputs", null, () => {
|
|
if (!this.inputs) {
|
|
this.inputs = [];
|
|
}
|
|
const target_number_of_inputs = this.widgets.find(w => w.name === "inputcount")["value"];
|
|
if(target_number_of_inputs===this.inputs.length)return;
|
|
|
|
if(target_number_of_inputs < this.inputs.length){
|
|
for(let i = this.inputs.length; i>=this.inputs_offset+target_number_of_inputs; i--)
|
|
this.removeInput(i)
|
|
}
|
|
else{
|
|
for(let i = this.inputs.length+1-this.inputs_offset; i <= target_number_of_inputs; ++i)
|
|
this.addInput(`mask_${i}`, this._type)
|
|
}
|
|
});
|
|
}
|
|
break;
|
|
|
|
case "GetMaskSizeAndCount":
|
|
const onGetMaskSizeConnectInput = nodeType.prototype.onConnectInput;
|
|
nodeType.prototype.onConnectInput = function (targetSlot, type, output, originNode, originSlot) {
|
|
const v = onGetMaskSizeConnectInput? onGetMaskSizeConnectInput.apply(this, arguments): undefined
|
|
this.outputs[1]["name"] = "width"
|
|
this.outputs[2]["name"] = "height"
|
|
this.outputs[3]["name"] = "count"
|
|
return v;
|
|
}
|
|
const onGetMaskSizeExecuted = nodeType.prototype.onExecuted;
|
|
nodeType.prototype.onExecuted = function(message) {
|
|
const r = onGetMaskSizeExecuted? onGetMaskSizeExecuted.apply(this,arguments): undefined
|
|
let values = message["text"].toString().split('x').map(Number);
|
|
this.outputs[1]["name"] = values[1] + " width"
|
|
this.outputs[2]["name"] = values[2] + " height"
|
|
this.outputs[3]["name"] = values[0] + " count"
|
|
return r
|
|
}
|
|
break;
|
|
|
|
case "GetImageSizeAndCount":
|
|
const onGetImageSizeConnectInput = nodeType.prototype.onConnectInput;
|
|
nodeType.prototype.onConnectInput = function (targetSlot, type, output, originNode, originSlot) {
|
|
const v = onGetImageSizeConnectInput? onGetImageSizeConnectInput.apply(this, arguments): undefined
|
|
this.outputs[1]["name"] = "width"
|
|
this.outputs[2]["name"] = "height"
|
|
this.outputs[3]["name"] = "count"
|
|
return v;
|
|
}
|
|
const onGetImageSizeExecuted = nodeType.prototype.onExecuted;
|
|
nodeType.prototype.onExecuted = function(message) {
|
|
const r = onGetImageSizeExecuted? onGetImageSizeExecuted.apply(this,arguments): undefined
|
|
let values = message["text"].toString().split('x').map(Number);
|
|
this.outputs[1]["name"] = values[1] + " width"
|
|
this.outputs[2]["name"] = values[2] + " height"
|
|
this.outputs[3]["name"] = values[0] + " count"
|
|
return r
|
|
}
|
|
break;
|
|
|
|
case "PreviewAnimation":
|
|
const onPreviewAnimationConnectInput = nodeType.prototype.onConnectInput;
|
|
nodeType.prototype.onConnectInput = function (targetSlot, type, output, originNode, originSlot) {
|
|
const v = onPreviewAnimationConnectInput? onPreviewAnimationConnectInput.apply(this, arguments): undefined
|
|
this.title = "Preview Animation"
|
|
return v;
|
|
}
|
|
const onPreviewAnimationExecuted = nodeType.prototype.onExecuted;
|
|
nodeType.prototype.onExecuted = function(message) {
|
|
const r = onPreviewAnimationExecuted? onPreviewAnimationExecuted.apply(this,arguments): undefined
|
|
let values = message["text"].toString();
|
|
this.title = "Preview Animation " + values
|
|
return r
|
|
}
|
|
break;
|
|
|
|
case "VRAM_Debug":
|
|
const onVRAM_DebugConnectInput = nodeType.prototype.onConnectInput;
|
|
nodeType.prototype.onConnectInput = function (targetSlot, type, output, originNode, originSlot) {
|
|
const v = onVRAM_DebugConnectInput? onVRAM_DebugConnectInput.apply(this, arguments): undefined
|
|
this.outputs[3]["name"] = "freemem_before"
|
|
this.outputs[4]["name"] = "freemem_after"
|
|
return v;
|
|
}
|
|
const onVRAM_DebugExecuted = nodeType.prototype.onExecuted;
|
|
nodeType.prototype.onExecuted = function(message) {
|
|
const r = onVRAM_DebugExecuted? onVRAM_DebugExecuted.apply(this,arguments): undefined
|
|
let values = message["text"].toString().split('x');
|
|
this.outputs[3]["name"] = values[0] + " freemem_before"
|
|
this.outputs[4]["name"] = values[1] + " freemem_after"
|
|
return r
|
|
}
|
|
break;
|
|
|
|
case "JoinStringMulti":
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
this._type = "STRING"
|
|
this.inputs_offset = nodeData.name.includes("selective")?1:0
|
|
this.addWidget("button", "Update inputs", null, () => {
|
|
if (!this.inputs) {
|
|
this.inputs = [];
|
|
}
|
|
const target_number_of_inputs = this.widgets.find(w => w.name === "inputcount")["value"];
|
|
if(target_number_of_inputs===this.inputs.length)return;
|
|
|
|
if(target_number_of_inputs < this.inputs.length){
|
|
for(let i = this.inputs.length; i>=this.inputs_offset+target_number_of_inputs; i--)
|
|
this.removeInput(i)
|
|
}
|
|
else{
|
|
for(let i = this.inputs.length+1-this.inputs_offset; i <= target_number_of_inputs; ++i)
|
|
this.addInput(`string_${i}`, this._type)
|
|
}
|
|
});
|
|
}
|
|
break;
|
|
case "SoundReactive":
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
let audioContext;
|
|
let microphoneStream;
|
|
let animationFrameId;
|
|
let analyser;
|
|
let dataArray;
|
|
let startRangeHz;
|
|
let endRangeHz;
|
|
let smoothingFactor = 0.5;
|
|
let smoothedSoundLevel = 0;
|
|
|
|
|
|
const updateWidgetValueInRealTime = () => {
|
|
|
|
if (analyser && dataArray) {
|
|
analyser.getByteFrequencyData(dataArray);
|
|
|
|
const startRangeHzWidget = this.widgets.find(w => w.name === "start_range_hz");
|
|
if (startRangeHzWidget) startRangeHz = startRangeHzWidget.value;
|
|
const endRangeHzWidget = this.widgets.find(w => w.name === "end_range_hz");
|
|
if (endRangeHzWidget) endRangeHz = endRangeHzWidget.value;
|
|
const smoothingFactorWidget = this.widgets.find(w => w.name === "smoothing_factor");
|
|
if (smoothingFactorWidget) smoothingFactor = smoothingFactorWidget.value;
|
|
|
|
|
|
const frequencyBinWidth = audioContext.sampleRate / analyser.fftSize;
|
|
|
|
const startRangeIndex = Math.floor(startRangeHz / frequencyBinWidth);
|
|
const endRangeIndex = Math.floor(endRangeHz / frequencyBinWidth);
|
|
|
|
|
|
const calculateAverage = (start, end) => {
|
|
const sum = dataArray.slice(start, end).reduce((acc, val) => acc + val, 0);
|
|
const average = sum / (end - start);
|
|
|
|
|
|
smoothedSoundLevel = (average * (1 - smoothingFactor)) + (smoothedSoundLevel * smoothingFactor);
|
|
return smoothedSoundLevel;
|
|
};
|
|
|
|
const soundLevel = calculateAverage(startRangeIndex, endRangeIndex);
|
|
|
|
|
|
|
|
const lowLevelWidget = this.widgets.find(w => w.name === "sound_level");
|
|
if (lowLevelWidget) lowLevelWidget.value = soundLevel;
|
|
|
|
animationFrameId = requestAnimationFrame(updateWidgetValueInRealTime);
|
|
}
|
|
};
|
|
|
|
|
|
const startMicrophoneCapture = () => {
|
|
|
|
if (!audioContext) {
|
|
audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
|
|
|
console.log(`Sample rate: ${audioContext.sampleRate}Hz`);
|
|
analyser = audioContext.createAnalyser();
|
|
analyser.fftSize = 2048;
|
|
dataArray = new Uint8Array(analyser.frequencyBinCount);
|
|
|
|
const lowRangeWidget = this.widgets.find(w => w.name === "low_range_hz");
|
|
if (lowRangeWidget) startRangeHz = lowRangeWidget.value;
|
|
|
|
const midRangeWidget = this.widgets.find(w => w.name === "mid_range_hz");
|
|
if (midRangeWidget) endRangeHz = midRangeWidget.value;
|
|
}
|
|
|
|
navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {
|
|
microphoneStream = stream;
|
|
const microphone = audioContext.createMediaStreamSource(stream);
|
|
microphone.connect(analyser);
|
|
updateWidgetValueInRealTime();
|
|
}).catch(error => {
|
|
console.error('Access to microphone was denied or an error occurred:', error);
|
|
});
|
|
};
|
|
|
|
|
|
const stopMicrophoneCapture = () => {
|
|
if (animationFrameId) {
|
|
cancelAnimationFrame(animationFrameId);
|
|
}
|
|
if (microphoneStream) {
|
|
microphoneStream.getTracks().forEach(track => track.stop());
|
|
}
|
|
if (audioContext) {
|
|
audioContext.close();
|
|
|
|
audioContext = null;
|
|
}
|
|
};
|
|
|
|
|
|
this.addWidget("button", "Start mic capture", null, startMicrophoneCapture);
|
|
|
|
|
|
this.addWidget("button", "Stop mic capture", null, stopMicrophoneCapture);
|
|
};
|
|
break;
|
|
|
|
}
|
|
|
|
},
|
|
async setup() {
|
|
|
|
const originalComputeVisibleNodes = LGraphCanvas.prototype.computeVisibleNodes;
|
|
LGraphCanvas.prototype.computeVisibleNodes = function () {
|
|
const visibleNodesSet = new Set(originalComputeVisibleNodes.apply(this, arguments));
|
|
for (const node of this.graph._nodes) {
|
|
if ((node.type === "SetNode" || node.type === "GetNode") && node.drawConnection) {
|
|
visibleNodesSet.add(node);
|
|
}
|
|
}
|
|
return Array.from(visibleNodesSet);
|
|
};
|
|
|
|
}
|
|
}); |