Преглед изворни кода

start of implementation for processes with more than one input file

Jonathan Higgins пре 5 месеци
родитељ
комит
ed46e2ae2a
4 измењених фајлова са 107 додато и 34 уклоњено
  1. 44 0
      scenes/Nodes/nodes.tscn
  2. 11 0
      scenes/main/process_help.json
  3. 1 0
      scenes/main/scripts/graph_edit.gd
  4. 51 34
      scenes/main/scripts/run_thread.gd

+ 44 - 0
scenes/Nodes/nodes.tscn

@@ -802,6 +802,50 @@ size_flags_horizontal = 3
 text = "+"
 text = "+"
 metadata/calc = "+"
 metadata/calc = "+"
 
 
+[node name="GraphNode" type="GraphNode" parent="."]
+layout_mode = 0
+offset_left = 1273.0
+offset_top = 422.0
+offset_right = 1615.0
+offset_bottom = 509.0
+slot/0/left_enabled = true
+slot/0/left_type = 0
+slot/0/left_color = Color(1, 1, 1, 1)
+slot/0/left_icon = null
+slot/0/right_enabled = false
+slot/0/right_type = 0
+slot/0/right_color = Color(1, 1, 1, 1)
+slot/0/right_icon = null
+slot/0/draw_stylebox = true
+slot/1/left_enabled = true
+slot/1/left_type = 0
+slot/1/left_color = Color(1, 1, 1, 1)
+slot/1/left_icon = null
+slot/1/right_enabled = false
+slot/1/right_type = 0
+slot/1/right_color = Color(1, 1, 1, 1)
+slot/1/right_icon = null
+slot/1/draw_stylebox = true
+slot/2/left_enabled = false
+slot/2/left_type = 0
+slot/2/left_color = Color(1, 1, 1, 1)
+slot/2/left_icon = null
+slot/2/right_enabled = false
+slot/2/right_type = 0
+slot/2/right_color = Color(1, 1, 1, 1)
+slot/2/right_icon = null
+slot/2/draw_stylebox = true
+
+[node name="Control" type="Control" parent="GraphNode"]
+custom_minimum_size = Vector2(0, 20)
+layout_mode = 2
+
+[node name="Control2" type="Control" parent="GraphNode"]
+layout_mode = 2
+
+[node name="HSlider" type="HSlider" parent="GraphNode"]
+layout_mode = 2
+
 [connection signal="text_submitted" from="outputfile/FileNameField" to="outputfile" method="_on_file_name_field_text_submitted"]
 [connection signal="text_submitted" from="outputfile/FileNameField" to="outputfile" method="_on_file_name_field_text_submitted"]
 [connection signal="toggled" from="outputfile/DeleteIntermediateFilesToggle" to="outputfile" method="_on_delete_intermediate_files_toggle_toggled"]
 [connection signal="toggled" from="outputfile/DeleteIntermediateFilesToggle" to="outputfile" method="_on_delete_intermediate_files_toggle_toggled"]
 [connection signal="toggled" from="outputfile/ReuseFolderToggle" to="outputfile" method="_on_reuse_folder_toggle_toggled"]
 [connection signal="toggled" from="outputfile/ReuseFolderToggle" to="outputfile" method="_on_reuse_folder_toggle_toggled"]

+ 11 - 0
scenes/main/process_help.json

@@ -2463,6 +2463,17 @@
 	"subcategory": "misc",
 	"subcategory": "misc",
 	"title": "Append Silence"
 	"title": "Append Silence"
   },
   },
+  "modify_radical_6": {
+	"category": "time",
+	"description": "This process takes two inputs and multiples them together using a four-quadrant multiplier. Unlike amplitude modulation this allows the bipoloar mulitplier to go negative, inverting the input sounds phase. In sound terms this will produce two sounds layered together, the sum of input and modulator frequencies and the difference between the input and modulator frequencies and the carrier will dissapear. ",
+	"inputtype": "[0, 0]",
+	"outputtype": "[0]",
+	"parameters": {},
+	"short_description": "Multiply two sounds together",
+	"stereo": true,
+	"subcategory": "misc",
+	"title": "Cross Modulation"
+  },
   "housekeep_extract_4": {
   "housekeep_extract_4": {
 	"category": "time",
 	"category": "time",
 	"description": "This process is intended for removing DC offset from a soundfile. You can specify how much the signal should be moved away from the 0 crossing line. It can also be used to deliberately add a DC offset into the sound file before further processing. For processes in the Distort catagory this will allow for an asymetrical application of their processing providing different timbres. Note, working this way is not how the processes are intended to be used and may produce errors on runtime and unpredictable results. Playing signals with significant DC bias in them is not good for the longterm health of your loudspeakers. If you do deliberately add a DC offset, you should run the process in the opposite direction after you are done processing to remove the DC bias. ",
 	"description": "This process is intended for removing DC offset from a soundfile. You can specify how much the signal should be moved away from the 0 crossing line. It can also be used to deliberately add a DC offset into the sound file before further processing. For processes in the Distort catagory this will allow for an asymetrical application of their processing providing different timbres. Note, working this way is not how the processes are intended to be used and may produce errors on runtime and unpredictable results. Playing signals with significant DC bias in them is not good for the longterm health of your loudspeakers. If you do deliberately add a DC offset, you should run the process in the opposite direction after you are done processing to remove the DC bias. ",

+ 1 - 0
scenes/main/scripts/graph_edit.gd

@@ -80,6 +80,7 @@ func _make_node(command: String, skip_undo_redo := false) -> GraphNode:
 			for i in range(portcount):
 			for i in range(portcount):
 				#add a number of control nodes equal to whatever is higher input or output ports
 				#add a number of control nodes equal to whatever is higher input or output ports
 				var control = Control.new()
 				var control = Control.new()
+				control.custom_minimum_size.y = 20
 				graphnode.add_child(control)
 				graphnode.add_child(control)
 				
 				
 				#check if input or output is enabled
 				#check if input or output is enabled

+ 51 - 34
scenes/main/scripts/run_thread.gd

@@ -99,7 +99,7 @@ func run_thread_with_branches():
 						#check if it can find any valid connections
 						#check if it can find any valid connections
 						var connected = false
 						var connected = false
 						for conn in connections:
 						for conn in connections:
-							if conn["from_node"] == name and conn["to_port"] == i:
+							if conn["from_node"] == name and conn["from_port"] == i:
 								connected = true
 								connected = true
 								break
 								break
 						#if no valid connections are found break the for loop to skip checking other inputs and set include to false
 						#if no valid connections are found break the for loop to skip checking other inputs and set include to false
@@ -180,33 +180,47 @@ func run_thread_with_branches():
 		else:
 		else:
 			progress_label.text = "Running process: " + node.get_title()
 			progress_label.text = "Running process: " + node.get_title()
 		# Find upstream nodes connected to the current node
 		# Find upstream nodes connected to the current node
-		var inputs = reverse_graph[node_name]
-		var input_files = []
-		for input_node in inputs:
-			input_files.append(output_files[input_node])
-
-		# Merge inputs if this node has more than one input
-		if input_files.size() > 1:
-			# Prepare final merge output file name
-			var runmerge = await merge_many_files(process_count, input_files)
-			var merge_output = runmerge[0]
-			var converted_files = runmerge[1]
-
-			# Track the output and intermediate files
-			current_infile = merge_output
-			
-			if control_script.delete_intermediate_outputs:
-				intermediate_files.append(merge_output)
-				for f in converted_files:
-					intermediate_files.append(f)
-
-		# If only one input, use that
-		elif input_files.size() == 1:
-			current_infile = input_files[0]
+		# Build an array of all inlet connections
+		var input_connections := []
+		for conn in connections:
+			if conn["to_node"] == node_name:
+				input_connections.append(conn)
+		input_connections.sort_custom(func(a, b): return a["to_port"] < b["to_port"])
+		
+		#build a dictionary with all inputs sorted by inlet number
+		var inlet_inputs = {}
+
+		for conn in input_connections:
+			var inlet_idx = conn["to_port"]
+			var upstream_node = conn["from_node"]
+			if output_files.has(upstream_node):
+				if not inlet_inputs.has(inlet_idx):
+					inlet_inputs[inlet_idx] = []
+				inlet_inputs[inlet_idx].append(output_files[upstream_node])
+
+		# Merge inputs if inlet has more than one input and build infile dictionary
+		var current_infiles = {} #dictionary to store input files by inlet number
+
+		for inlet_idx in inlet_inputs.keys():
+			var files = inlet_inputs[inlet_idx]
+			if files.size() > 1: #if more than one file mix them together
+				var runmerge = await merge_many_files(process_count, files)
+				var merge_output = runmerge[0] #mixed output file name
+				var converted_files = runmerge[1] #intermediate files created from merge
+
+				current_infiles[inlet_idx] = merge_output #input filename added to dictionary sorted by inlet number
+				
+				#add intermediate files to delete list if toggled
+				if control_script.delete_intermediate_outputs:
+					intermediate_files.append(merge_output)
+					for f in converted_files:
+						intermediate_files.append(f)
+			elif files.size() == 1:
+				current_infiles[inlet_idx] = files[0] #only one file, do not merge add to dictionary
 
 
-		else:
-			#if no input i need to skip the node
-			pass
+			else:
+				#if no input i need to skip the node
+				pass
 		
 		
 		#check if node is some form of input node
 		#check if node is some form of input node
 		if node.get_input_port_count() == 0:
 		if node.get_input_port_count() == 0:
@@ -244,7 +258,7 @@ func run_thread_with_branches():
 				process_count += 1
 				process_count += 1
 			else: #not an audio file must be synthesis
 			else: #not an audio file must be synthesis
 				var slider_data = _get_slider_values_ordered(node)
 				var slider_data = _get_slider_values_ordered(node)
-				var makeprocess = await make_process(node, process_count, "none", slider_data)
+				var makeprocess = await make_process(node, process_count, [], slider_data)
 				# run the command
 				# run the command
 				await run_command(makeprocess[0], makeprocess[3])
 				await run_command(makeprocess[0], makeprocess[3])
 				await get_tree().process_frame
 				await get_tree().process_frame
@@ -384,9 +398,11 @@ func run_thread_with_branches():
 						intermediate_files.erase(current_infile)
 						intermediate_files.erase(current_infile)
 				else:
 				else:
 					#Detect if input file is mono or stereo
 					#Detect if input file is mono or stereo
-					var input_stereo = await is_stereo(current_infile)
+					#var input_stereo = await is_stereo(current_infile)
+					var input_stereo = true #bypassing stereo check just for testing need to reimplement
 					if input_stereo == true:
 					if input_stereo == true:
 						if node.get_meta("stereo_input") == true: #audio file is stereo and process is stereo, run file through process
 						if node.get_meta("stereo_input") == true: #audio file is stereo and process is stereo, run file through process
+							current_infile = current_infiles.values()
 							var makeprocess = await make_process(node, process_count, current_infile, slider_data)
 							var makeprocess = await make_process(node, process_count, current_infile, slider_data)
 							# run the command
 							# run the command
 							await run_command(makeprocess[0], makeprocess[3])
 							await run_command(makeprocess[0], makeprocess[3])
@@ -667,7 +683,7 @@ func _get_slider_values_ordered(node: Node) -> Array:
 
 
 
 
 
 
-func make_process(node: Node, process_count: int, current_infile: String, slider_data: Array) -> Array:
+func make_process(node: Node, process_count: int, current_infile: Array, slider_data: Array) -> Array:
 	# Determine output extension: .wav or .ana based on the node's slot type
 	# Determine output extension: .wav or .ana based on the node's slot type
 	var extension = ".wav" if node.get_slot_type_right(0) == 0 else ".ana"
 	var extension = ".wav" if node.get_slot_type_right(0) == 0 else ".ana"
 
 
@@ -679,9 +695,10 @@ func make_process(node: Node, process_count: int, current_infile: String, slider
 	command_name = command_name.split("_", true, 1)
 	command_name = command_name.split("_", true, 1)
 	var command = "%s/%s" %[control_script.cdpprogs_location, command_name[0]]
 	var command = "%s/%s" %[control_script.cdpprogs_location, command_name[0]]
 	var args = command_name[1].split("_", true, 1)
 	var args = command_name[1].split("_", true, 1)
-	if current_infile != "none":
-		#check if input is none, e.g. synthesis nodes, otherwise append input file to arguments
-		args.append(current_infile)
+	if current_infile.size() > 0:
+		#check if input is empty, e.g. synthesis nodes, otherwise append input file to arguments
+		for file in current_infile:
+			args.append(file)
 	args.append(output_file)
 	args.append(output_file)
 
 
 	# Start building the command line windows i dont think this is used anymore
 	# Start building the command line windows i dont think this is used anymore
@@ -714,7 +731,7 @@ func make_process(node: Node, process_count: int, current_infile: String, slider
 				
 				
 				#get length of input file in seconds
 				#get length of input file in seconds
 				var infile_length = 1 #set infile length to dummy value just incase it does get used where it shouldn't to avoid crashes
 				var infile_length = 1 #set infile length to dummy value just incase it does get used where it shouldn't to avoid crashes
-				if current_infile != "none":
+				if current_infile.size() > 0:
 					infile_length = await run_command(control_script.cdpprogs_location + "/sfprops", ["-d", current_infile])
 					infile_length = await run_command(control_script.cdpprogs_location + "/sfprops", ["-d", current_infile])
 					infile_length = float(infile_length.strip_edges())
 					infile_length = float(infile_length.strip_edges())