-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathOP-GraphEditor.gd
158 lines (116 loc) · 4.34 KB
/
OP-GraphEditor.gd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#A lot of FM Instrument modular structure lives here, for now....
extends GraphEdit
#A temp list of connections used to validate an algorithm.
var test_connections = {}
var connections = {} #Operator connections in an algorithm
var connections_valid = false
var dirty = false setget set_dirty #Indicates if the node graph is out of date.
signal changed
func set_dirty(val):
dirty = val
emit_signal("changed", dirty)
func _ready():
add_valid_connection_type(0,1)
add_valid_connection_type(1,0)
add_valid_left_disconnect_type(0)
add_valid_left_disconnect_type(1)
add_valid_right_disconnect_type(0)
add_valid_right_disconnect_type(1)
for o in get_children():
if o is GraphNode:
o.title = o.name
#Wires up the nodes based on an input string. Kinda fragile.....
func wire_up(input:String):
clear_connections()
#Get all operators connection data
var ops = input.split(";", false)
for opInfo in ops:
var opname = opInfo.split("=", false)[0]
var op = get_node_or_null(opname)
if !op:
print ("GraphEdit: Can't find operator %s!" % opname)
continue
var cs = opInfo.split("=", false)[1] #Connections to current operator
for cname in cs.split(",", false):
var connection = get_node_or_null("cname")
if !cname:
print ("GraphEdit: Can't find operator %s!" % opname)
continue
else: #Connect our OP node to cname.
var err = connect_node(cname, 0, opname, 0)
if err != OK: print("GraphEdit: Failed to link %s and %s." % [opname, cname])
func _on_GraphEdit_connection_request(from, from_slot, to, to_slot):
# prints("request from", from, "slot", from_slot, "to", to, ", slot", to_slot)
if from != to:
connect_node(from, from_slot, to, to_slot)
set_dirty( true )
else:
prints("Warning: Attempting to connect", from, "to itself")
global.custom_algo = get_connection_list()
func _on_GraphEdit_disconnection_request(from, from_slot, to, to_slot):
disconnect_node(from, from_slot, to, to_slot)
set_dirty(true)
global.custom_algo = get_connection_list()
func validate():
var connection_list = get_connection_list()
test_connections.clear()
connections.clear()
#Assemble a dictionary of everything each block's connected to.
for o in connection_list:
var key = o["to"]
if !test_connections.has(key):
test_connections[key] = {}
# connections[key].append(o["from"])
test_connections[key][ o["from"] ] = true
# print(test_connections, "\n", get_connection_list())
#First, check if the speakers are connected to anything.
if !test_connections.has("Output") or test_connections["Output"].empty():
OS.alert("Output isn't connected to anything!")
return
#Now make sure there's no infinite loops in the operator connections.
var is_invalid:bool = validate_loop("Output", {})
if is_invalid:
connections_valid = false
OS.alert("Algorithm validation failed.")
return
else:
#Validation passed. Assign connections.
connections = test_connections
connections_valid = true
print (connections)
#For the C# engine: Tell the mixer to assign connections.
#First, construct a string out of the connections because
#the marshalling of nested dictionaries is face-melting
var cs:String = ""
for connection in connections:
var ops:String = connection + "="
for operator in connections[connection]:
ops += operator + ","
ops = ops.rstrip(",")
cs += ops + ";"
cs = cs.rstrip(";")
print(cs)
owner.get_node("Audio").UpdatePatchFromString(cs)
# OS.alert("Validation OK.")
set_dirty(false)
#Recursive function which validates an algorithm is free of infinite loops.
#TODO: Doesn't work with common modulators! Try to check only the input side
# of the connections for loops?
func validate_loop(me, prior_connections, caller="?") -> bool:
var out = false #Return true if there's a loop detected.
prior_connections[me] = true
var next_connections:Dictionary
if test_connections.has(me):
next_connections = test_connections[me]
else:
next_connections = {}
# print(me, " next: ", next_connections, " prior: ", caller, ", ",
# prior_connections)
#Check all the next connections for a prior connection.
for c in next_connections:
if prior_connections.has(c) and c != "Output":
OS.alert("Loop detected at %s to %s" % [me, c])
return true
else: #So far so good. Recurse.
out = out or validate_loop(c, prior_connections.duplicate(), me)
return out