Browse Source

started adding initial support for synthesis nodes

Jonathan Higgins 6 months ago
parent
commit
5e5fb9e277
4 changed files with 183 additions and 38 deletions
  1. 87 0
      scenes/main/process_help.json
  2. 58 35
      scenes/main/scripts/run_thread.gd
  3. 2 0
      scenes/menu/explore_menu.gd
  4. 36 3
      scenes/menu/menu.tscn

+ 87 - 0
scenes/main/process_help.json

@@ -2670,6 +2670,93 @@
 	"subcategory": "reverb",
 	"title": "Reverb"
   },
+  "synth_wave_1": {
+	"category": "time",
+	"description": "This process generates a constant sine tone. The pitch of the sine tone as well as its amplitude can be set to vary over time. This synth node is particularly useful for testing the various Distort processes to get a feel for how they change a sound.",
+	"inputtype": "[]",
+	"outputtype": "[0]",
+	"parameters": {
+	  "param1": {
+		"paramname": "Sample Rate",
+		"paramdescription": "The sample rate of the generated sine wave",
+		"automatable": false,
+		"time": false,
+		"min": false,
+		"max": false,
+		"flag": "",
+		"minrange": 48000.0,
+		"maxrange": 96000.0,
+		"step": 48000.0,
+		"value": 48000.0,
+		"exponential": false,
+		"uitype": "hslider"
+	  },
+	  "param2": {
+		"paramname": "Mono/Stereo",
+		"paramdescription": "The number of output channels in the sound",
+		"automatable": false,
+		"time": false,
+		"min": false,
+		"max": false,
+		"flag": "",
+		"minrange": 1.0,
+		"maxrange": 2.0,
+		"step": 1.0,
+		"value": 1.0,
+		"exponential": false,
+		"uitype": "hslider"
+	  },
+	  "param3": {
+		"paramname": "Duration",
+		"paramdescription": "The length in seconds to generate the waveform for",
+		"automatable": false,
+		"time": false,
+		"min": false,
+		"max": false,
+		"flag": "",
+		"minrange": 0.5,
+		"maxrange": 720.0,
+		"step": 0.01,
+		"value": 30.0,
+		"exponential": true,
+		"uitype": "hslider"
+	  },
+	  "param4": {
+		"paramname": "Frequency",
+		"paramdescription": "The pitch of the waveform",
+		"automatable": true,
+		"time": false,
+		"min": false,
+		"max": false,
+		"flag": "",
+		"minrange": 20.0,
+		"maxrange": 20000.0,
+		"step": 0.01,
+		"value": 220.0,
+		"exponential": true,
+		"uitype": "hslider"
+	  },
+	  "param5": {
+		"paramname": "Amplitude",
+		"paramdescription": "The output gain of the waveform",
+		"automatable": true,
+		"time": false,
+		"min": false,
+		"max": false,
+		"flag": "-a",
+		"minrange": 0.0,
+		"maxrange": 1.0,
+		"step": 0.01,
+		"value": 0.6,
+		"exponential": false,
+		"uitype": "hslider"
+	  }
+	},
+	"short_description": "Generates a sine tone",
+	"stereo": true,
+	"subcategory": "synthesis",
+	"title": "Sine Wave Generator"
+  },
   "blur_chorus_5": {
 	"category": "pvoc",
 	"description": "This process attempts to achieve a chorusing effect by randomising the amplitude and frequency values of the partials. If very large amplitude values are used, the sound will turn to noise. The chorusing effect itself is achieved by values just a little above 1. Values of 2 or 3 begin to create a granular effect, and values of 10, 100 and 1000 create more and more noise.\n",

+ 58 - 35
scenes/main/scripts/run_thread.gd

@@ -204,43 +204,63 @@ func run_thread_with_branches():
 		elif input_files.size() == 1:
 			current_infile = input_files[0]
 
-		## If no input, use the original input file
 		else:
 			#if no input i need to skip the node
 			pass
 		
-		if node.get_meta("command") == "inputfile":
-			#get the inputfile from the nodes meta
-			var loadedfile = node.get_node("AudioPlayer").get_meta("inputfile")
-			#get wether trim has been enabled
-			var trimfile = node.get_node("AudioPlayer").get_meta("trimfile")
-			
-			#if trim is enabled trim the file
-			if trimfile == true:
-				#get the start and end points
-				var start = node.get_node("AudioPlayer").get_meta("trimpoints")[0]
-				var end = node.get_node("AudioPlayer").get_meta("trimpoints")[1]
+		#check if node is some form of input node
+		if node.get_input_port_count() == 0:
+			if node.get_meta("command") == "inputfile":
+				#get the inputfile from the nodes meta
+				var loadedfile = node.get_node("AudioPlayer").get_meta("inputfile")
+				#get wether trim has been enabled
+				var trimfile = node.get_node("AudioPlayer").get_meta("trimfile")
 				
-				if process_cancelled:
-					#exit out of process if cancelled
-					progress_label.text = "Thread Stopped"
-					log_console("[b]Thread Stopped[/b]", true)
-					return
+				#if trim is enabled trim the file
+				if trimfile == true:
+					#get the start and end points
+					var start = node.get_node("AudioPlayer").get_meta("trimpoints")[0]
+					var end = node.get_node("AudioPlayer").get_meta("trimpoints")[1]
+					
+					if process_cancelled:
+						#exit out of process if cancelled
+						progress_label.text = "Thread Stopped"
+						log_console("[b]Thread Stopped[/b]", true)
+						return
+					else:
+						progress_label.text = "Trimming input audio"
+					await run_command(control_script.cdpprogs_location + "/sfedit", ["cut", "1", loadedfile, "%s_%d_input_trim.wav" % [Global.outfile, process_count], str(start), str(end)])
+					
+					output_files[node_name] =  "%s_%d_input_trim.wav" % [Global.outfile, process_count]
+					
+					# Mark trimmed file for cleanup if needed
+					if control_script.delete_intermediate_outputs:
+						intermediate_files.append("%s_%d_input_trim.wav" % [Global.outfile, process_count])
+					progress_bar.value += progress_step
 				else:
-					progress_label.text = "Trimming input audio"
-				await run_command(control_script.cdpprogs_location + "/sfedit", ["cut", "1", loadedfile, "%s_%d_input_trim.wav" % [Global.outfile, process_count], str(start), str(end)])
-				
-				output_files[node_name] =  "%s_%d_input_trim.wav" % [Global.outfile, process_count]
+					#if trim not enabled pass the loaded file
+					output_files[node_name] =  loadedfile
+					
+				process_count += 1
+			else: #not an audio file must be synthesis
+				var slider_data = _get_slider_values_ordered(node)
+				var makeprocess = await make_process(node, process_count, "none", slider_data)
+				# run the command
+				await run_command(makeprocess[0], makeprocess[3])
+				await get_tree().process_frame
+				var output_file = makeprocess[1]
 				
-				# Mark trimmed file for cleanup if needed
+
+				# Store output file path for this node
+				output_files[node_name] = output_file
+
+				# Mark file for cleanup if needed
 				if control_script.delete_intermediate_outputs:
-					intermediate_files.append("%s_%d_input_trim.wav" % [Global.outfile, process_count])
-				progress_bar.value += progress_step
-			else:
-				#if trim not enabled pass the loaded file
-				output_files[node_name] =  loadedfile
-				
-			process_count += 1
+					for file in makeprocess[2]:
+						breakfiles.append(file)
+					intermediate_files.append(output_file)
+					
+				process_count += 1
 		else:
 			# Build the command for the current node's audio processing
 			var slider_data = _get_slider_values_ordered(node)
@@ -644,11 +664,13 @@ func make_process(node: Node, process_count: int, current_infile: String, slider
 	command_name = command_name.split("_", true, 1)
 	var command = "%s/%s" %[control_script.cdpprogs_location, command_name[0]]
 	var args = command_name[1].split("_", true, 1)
-	args.append(current_infile)
+	if current_infile != "none":
+		#check if input is none, e.g. synthesis nodes, otherwise append input file to arguments
+		args.append(current_infile)
 	args.append(output_file)
 
-	# Start building the command line windows
-	var line = "%s/%s \"%s\" \"%s\" " % [control_script.cdpprogs_location, command_name, current_infile, output_file]
+	# Start building the command line windows i dont think this is used anymore
+	#var line = "%s/%s \"%s\" \"%s\" " % [control_script.cdpprogs_location, command_name, current_infile, output_file]
 	#mac
 
 	
@@ -698,7 +720,7 @@ func make_process(node: Node, process_count: int, current_infile: String, slider
 			write_breakfile(calculated_brk, brk_file_path)
 			
 			#append text file in place of value
-			line += ("\"%s\" " % brk_file_path)
+			#line += ("\"%s\" " % brk_file_path)
 			args.append(brk_file_path)
 			
 			cleanup.append(brk_file_path)
@@ -707,7 +729,7 @@ func make_process(node: Node, process_count: int, current_infile: String, slider
 				var infile_length = await run_command(control_script.cdpprogs_location + "/sfprops", ["-d", current_infile])
 				infile_length = float(infile_length.strip_edges())
 				value = infile_length * (value / 100) #calculate percentage time of the input file
-			line += ("%s%.2f " % [flag, value]) if flag.begins_with("-") else ("%.2f " % value)
+			#line += ("%s%.2f " % [flag, value]) if flag.begins_with("-") else ("%.2f " % value)
 			args.append(("%s%.2f " % [flag, value]) if flag.begins_with("-") else str(value))
 			
 		slider_count += 1
@@ -751,7 +773,8 @@ func path_exists_through_all_nodes() -> bool:
 			all_nodes[name] = child
 
 			var command = child.get_meta("command")
-			if command == "inputfile":
+			var type = command.get_slice("_", 0)
+			if command == "inputfile" or type == "synth":
 				input_node_names.append(name)
 			elif command == "outputfile":
 				output_node_name = name

+ 2 - 0
scenes/menu/explore_menu.gd

@@ -48,6 +48,8 @@ func fill_menu():
 				container = $"Control/select_effect/Time Domain/Misc/MarginContainer/ScrollContainer/MiscContainer"
 			elif subcategory == "reverb":
 				container = $"Control/select_effect/Time Domain/Reverb and Delay/MarginContainer/ScrollContainer/ReverbContainer"
+			elif subcategory == "synthesis":
+				container = $"Control/select_effect/Time Domain/Synthesis/MarginContainer/ScrollContainer/SynthesisContainer"
 			else:
 				continue
 		elif category == "pvoc":

+ 36 - 3
scenes/menu/menu.tscn

@@ -31,12 +31,11 @@ offset_right = 325.0
 offset_bottom = 250.0
 grow_horizontal = 2
 grow_vertical = 2
-current_tab = 1
+current_tab = 0
 
 [node name="Time Domain" type="TabContainer" parent="Control/select_effect"]
-visible = false
 layout_mode = 2
-current_tab = 3
+current_tab = 6
 metadata/_tab_index = 0
 
 [node name="Distort" type="VBoxContainer" parent="Control/select_effect/Time Domain"]
@@ -139,6 +138,7 @@ layout_mode = 2
 theme_override_constants/margin_bottom = 5
 
 [node name="Granulate" type="VBoxContainer" parent="Control/select_effect/Time Domain"]
+visible = false
 layout_mode = 2
 metadata/_tab_index = 3
 
@@ -214,7 +214,40 @@ horizontal_scroll_mode = 0
 custom_minimum_size = Vector2(620, 0)
 layout_mode = 2
 
+[node name="Synthesis" type="VBoxContainer" parent="Control/select_effect/Time Domain"]
+layout_mode = 2
+metadata/_tab_index = 6
+
+[node name="MarginContainer" type="MarginContainer" parent="Control/select_effect/Time Domain/Synthesis"]
+layout_mode = 2
+theme_override_constants/margin_left = 15
+theme_override_constants/margin_top = 10
+theme_override_constants/margin_right = 5
+theme_override_constants/margin_bottom = 10
+
+[node name="ScrollContainer" type="ScrollContainer" parent="Control/select_effect/Time Domain/Synthesis/MarginContainer"]
+custom_minimum_size = Vector2(620, 425)
+layout_mode = 2
+size_flags_horizontal = 0
+horizontal_scroll_mode = 0
+
+[node name="SynthesisContainer" type="VBoxContainer" parent="Control/select_effect/Time Domain/Synthesis/MarginContainer/ScrollContainer"]
+custom_minimum_size = Vector2(620, 0)
+layout_mode = 2
+
+[node name="Label" type="Label" parent="Control/select_effect/Time Domain/Synthesis/MarginContainer/ScrollContainer/SynthesisContainer"]
+custom_minimum_size = Vector2(620, 0)
+layout_mode = 2
+size_flags_horizontal = 4
+text = "Unlike the other nodes in SoundThread that all process sound, these processes synthesis sounds. These can be used as alternative sound sources but are also very useful as sound sources for testing out various other processes to get a feel for what they do."
+autowrap_mode = 3
+
+[node name="MarginContainer4" type="MarginContainer" parent="Control/select_effect/Time Domain/Synthesis/MarginContainer/ScrollContainer/SynthesisContainer"]
+layout_mode = 2
+theme_override_constants/margin_bottom = 5
+
 [node name="Frequency Domain" type="TabContainer" parent="Control/select_effect"]
+visible = false
 layout_mode = 2
 current_tab = 4
 metadata/_tab_index = 1