Browse Source

added saving and loading and started implementing example patches

Jonathan Higgins 7 months ago
parent
commit
893c82d0dd

+ 3 - 0
.godot/editor/NodeData.tres-folding-8cf375428e6a0e432d1b0d9e5082bc15.cfg

@@ -0,0 +1,3 @@
+[folding]
+
+sections_unfolded=PackedStringArray()

+ 1 - 1
.godot/editor/audioplayer.tscn-editstate-5c5be15cd7cbde82fbc3248f6958ab76.cfg

@@ -192,4 +192,4 @@ Game={
 "hide_selection": false,
 "select_mode": 0
 }
-selected_nodes=Array[NodePath]([NodePath("/root/@EditorNode@21272/@Panel@14/@VBoxContainer@15/DockHSplitLeftL/DockHSplitLeftR/DockHSplitMain/@VBoxContainer@26/DockVSplitCenter/@VSplitContainer@54/@VBoxContainer@55/@EditorMainScreen@102/MainScreen/@CanvasItemEditor@11482/@VSplitContainer@11134/@HSplitContainer@11136/@HSplitContainer@11138/@Control@11139/@SubViewportContainer@11140/@SubViewport@11141/Control")])
+selected_nodes=Array[NodePath]([NodePath("/root/@EditorNode@21272/@Panel@14/@VBoxContainer@15/DockHSplitLeftL/DockHSplitLeftR/DockHSplitMain/@VBoxContainer@26/DockVSplitCenter/@VSplitContainer@54/@VBoxContainer@55/@EditorMainScreen@102/MainScreen/@CanvasItemEditor@11482/@VSplitContainer@11134/@HSplitContainer@11136/@HSplitContainer@11138/@Control@11139/@SubViewportContainer@11140/@SubViewport@11141/Control/MenuBar/HelpButton")])

+ 3 - 3
.godot/editor/control.tscn-editstate-475cf43e2d21753002d8a2b4ccf5105f.cfg

@@ -5,10 +5,10 @@ Anim={
 }
 2D={
 "grid_offset": Vector2(0, 0),
-"grid_snap_active": false,
+"grid_snap_active": true,
 "grid_step": Vector2(8, 8),
 "grid_visibility": 1,
-"ofs": Vector2(-371.9, -83),
+"ofs": Vector2(-473.8, -45),
 "primary_grid_step": Vector2i(8, 8),
 "show_group_gizmos": true,
 "show_guides": true,
@@ -192,4 +192,4 @@ Game={
 "hide_selection": false,
 "select_mode": 0
 }
-selected_nodes=Array[NodePath]([NodePath("/root/@EditorNode@21272/@Panel@14/@VBoxContainer@15/DockHSplitLeftL/DockHSplitLeftR/DockHSplitMain/@VBoxContainer@26/DockVSplitCenter/@VSplitContainer@54/@VBoxContainer@55/@EditorMainScreen@102/MainScreen/@CanvasItemEditor@11482/@VSplitContainer@11134/@HSplitContainer@11136/@HSplitContainer@11138/@Control@11139/@SubViewportContainer@11140/@SubViewport@11141/Control")])
+selected_nodes=Array[NodePath]([NodePath("/root/@EditorNode@21272/@Panel@14/@VBoxContainer@15/DockHSplitLeftL/DockHSplitLeftR/DockHSplitMain/@VBoxContainer@26/DockVSplitCenter/@VSplitContainer@54/@VBoxContainer@55/@EditorMainScreen@102/MainScreen/@CanvasItemEditor@11482/@VSplitContainer@11134/@HSplitContainer@11136/@HSplitContainer@11138/@Control@11139/@SubViewportContainer@11140/@SubViewport@11141/Control/MenuBar/HelpButton")])

+ 1 - 1
.godot/editor/control.tscn-folding-475cf43e2d21753002d8a2b4ccf5105f.cfg

@@ -1,5 +1,5 @@
 [folding]
 
-node_unfolds=[NodePath("."), PackedStringArray("Layout"), NodePath("GraphEdit"), PackedStringArray("Layout", "Layout/Transform"), NodePath("NoLocationPopup"), PackedStringArray("Flags"), NodePath("NoInputPopup"), PackedStringArray("Flags"), NodePath("Console"), PackedStringArray("Flags"), NodePath("Console/Panel"), PackedStringArray("Layout", "Layout/Transform"), NodePath("Console/ConsoleOutput"), PackedStringArray("Layout")]
+node_unfolds=[NodePath("."), PackedStringArray("Layout"), NodePath("GraphEdit"), PackedStringArray("Layout", "Layout/Transform"), NodePath("NoLocationPopup"), PackedStringArray("Flags"), NodePath("NoInputPopup"), PackedStringArray("Flags"), NodePath("Console"), PackedStringArray("Flags"), NodePath("Console/Panel"), PackedStringArray("Layout", "Layout/Transform"), NodePath("Console/ConsoleOutput"), PackedStringArray("Layout"), NodePath("MenuBar"), PackedStringArray("Layout"), NodePath("MenuBar/FileButton"), PackedStringArray("item_count_array"), NodePath("MenuBar/SettingsButton"), PackedStringArray("item_count_array"), NodePath("MenuBar/HelpButton"), PackedStringArray("item_count_array")]
 resource_unfolds=[]
 nodes_folded=[NodePath("NoLocationPopup"), NodePath("NoInputPopup"), NodePath("MultipleConnectionsPopup"), NodePath("Console")]

+ 6 - 6
.godot/editor/create_recent.Node

@@ -1,14 +1,14 @@
+FileDialog
+Label
+PopupMenu
+ColorRect
+Panel
+MenuBar
 Button
 CodeEdit
-Label
 CheckButton
 HBoxContainer
-Panel
 Window
 Popup
 RichTextLabel
-FileDialog
 VBoxContainer
-ScrollContainer
-Control
-GraphNode

+ 1 - 0
.godot/editor/create_recent.Resource

@@ -0,0 +1 @@
+Resource

+ 4 - 4
.godot/editor/editor_layout.cfg

@@ -9,8 +9,8 @@ dock_filesystem_v_split_offset=0
 dock_filesystem_display_mode=0
 dock_filesystem_file_sort=0
 dock_filesystem_file_list_display_mode=1
-dock_filesystem_selected_paths=PackedStringArray("res://README.md")
-dock_filesystem_uncollapsed_paths=PackedStringArray("Favorites", "res://", "res://scenes/", "res://scenes/Nodes/", "res://scenes/menu/", "res://scenes/main/", "res://addons/", "res://addons/audio_preview/")
+dock_filesystem_selected_paths=PackedStringArray("res://config_handler.gd")
+dock_filesystem_uncollapsed_paths=PackedStringArray("Favorites", "res://", "res://scenes/main/", "res://addons/audio_preview/")
 dock_node_current_tab=0
 dock_history_include_scene=true
 dock_history_include_global=true
@@ -33,7 +33,7 @@ current_scene="res://scenes/main/control.tscn"
 center_split_offset=0
 selected_default_debugger_tab_idx=0
 selected_main_editor_idx=2
-selected_bottom_panel_item=1
+selected_bottom_panel_item=0
 
 [EditorWindow]
 
@@ -44,7 +44,7 @@ size=Vector2i(1152, 648)
 
 [ScriptEditor]
 
-open_scripts=["res://scenes/Nodes/audioplayer.gd", "res://addons/audio_preview/AudioStreamPreview.gd", "res://config_handler.gd", "res://scenes/main/control.gd", "res://scenes/Nodes/focus_accu_sliders.gd", "res://Global.gd", "res://scenes/main/graph_edit.gd", "res://scenes/Nodes/scatter_value.gd", "res://scenes/Nodes/valueslider.gd", "res://addons/audio_preview/voice_preview_generator.gd", "res://scenes/Nodes/waveform_preview.gd"]
+open_scripts=["res://scenes/Nodes/audioplayer.gd", "res://addons/audio_preview/AudioStreamPreview.gd", "res://config_handler.gd", "res://scenes/main/control.gd", "res://export_presets.cfg", "res://scenes/Nodes/focus_accu_sliders.gd", "res://Global.gd", "res://scenes/main/graph_edit.gd", "res://scenes/Nodes/scatter_value.gd", "res://scenes/Nodes/valueslider.gd", "res://addons/audio_preview/voice_preview_generator.gd", "res://scenes/Nodes/waveform_preview.gd"]
 selected_script="res://scenes/main/control.gd"
 open_help=[]
 script_split_offset=200

+ 0 - 0
.godot/editor/favorites.Resource


+ 2 - 0
.godot/editor/filesystem_update4

@@ -4,3 +4,5 @@ res://scenes/Nodes/nodes.tscn
 res://scenes/menu/menu.tscn
 res://scenes/Nodes/audioplayer.tscn
 res://scenes/main/control.gd
+res://scenes/main/graph_edit.gd
+res://config_handler.gd

+ 1 - 1
.godot/editor/menu.tscn-editstate-523ba9f1be4474a87fc09942b9fbb098.cfg

@@ -192,4 +192,4 @@ Game={
 "hide_selection": false,
 "select_mode": 0
 }
-selected_nodes=Array[NodePath]([NodePath("/root/@EditorNode@21272/@Panel@14/@VBoxContainer@15/DockHSplitLeftL/DockHSplitLeftR/DockHSplitMain/@VBoxContainer@26/DockVSplitCenter/@VSplitContainer@54/@VBoxContainer@55/@EditorMainScreen@102/MainScreen/@CanvasItemEditor@11482/@VSplitContainer@11134/@HSplitContainer@11136/@HSplitContainer@11138/@Control@11139/@SubViewportContainer@11140/@SubViewport@11141/Control")])
+selected_nodes=Array[NodePath]([NodePath("/root/@EditorNode@21272/@Panel@14/@VBoxContainer@15/DockHSplitLeftL/DockHSplitLeftR/DockHSplitMain/@VBoxContainer@26/DockVSplitCenter/@VSplitContainer@54/@VBoxContainer@55/@EditorMainScreen@102/MainScreen/@CanvasItemEditor@11482/@VSplitContainer@11134/@HSplitContainer@11136/@HSplitContainer@11138/@Control@11139/@SubViewportContainer@11140/@SubViewport@11141/Control/MenuBar/HelpButton")])

+ 2 - 2
.godot/editor/nodes.tscn-editstate-d18a50cdbd65798e64eea9469be45949.cfg

@@ -8,7 +8,7 @@ Anim={
 "grid_snap_active": false,
 "grid_step": Vector2(8, 8),
 "grid_visibility": 1,
-"ofs": Vector2(-363.513, 121.811),
+"ofs": Vector2(-253.998, -151.976),
 "primary_grid_step": Vector2i(8, 8),
 "show_group_gizmos": true,
 "show_guides": true,
@@ -192,4 +192,4 @@ Game={
 "hide_selection": false,
 "select_mode": 0
 }
-selected_nodes=Array[NodePath]([NodePath("/root/@EditorNode@21272/@Panel@14/@VBoxContainer@15/DockHSplitLeftL/DockHSplitLeftR/DockHSplitMain/@VBoxContainer@26/DockVSplitCenter/@VSplitContainer@54/@VBoxContainer@55/@EditorMainScreen@102/MainScreen/@CanvasItemEditor@11482/@VSplitContainer@11134/@HSplitContainer@11136/@HSplitContainer@11138/@Control@11139/@SubViewportContainer@11140/@SubViewport@11141/Control")])
+selected_nodes=Array[NodePath]([NodePath("/root/@EditorNode@21272/@Panel@14/@VBoxContainer@15/DockHSplitLeftL/DockHSplitLeftR/DockHSplitMain/@VBoxContainer@26/DockVSplitCenter/@VSplitContainer@54/@VBoxContainer@55/@EditorMainScreen@102/MainScreen/@CanvasItemEditor@11482/@VSplitContainer@11134/@HSplitContainer@11136/@HSplitContainer@11138/@Control@11139/@SubViewportContainer@11140/@SubViewport@11141/Control/MenuBar/HelpButton")])

File diff suppressed because it is too large
+ 0 - 0
.godot/editor/nodes.tscn-folding-d18a50cdbd65798e64eea9469be45949.cfg


+ 3 - 3
.godot/editor/project_metadata.cfg

@@ -5,14 +5,14 @@ use_advanced_connections=false
 
 [dialog_bounds]
 
-create_new_node=Rect2(510, 190, 900, 700)
+create_new_node=Rect2(808, 324, 900, 700)
 project_settings=Rect2(2409, 223, 1200, 700)
 export=Rect2(2386, 375, 900, 500)
 
 [recent_files]
 
 scenes=["res://scenes/Nodes/audioplayer.tscn", "res://scenes/menu/menu.tscn", "res://scenes/Nodes/nodes.tscn", "res://scenes/Nodes/valueslider.tscn", "res://scenes/main/control.tscn", "res://node_2d.tscn", "res://menu.tscn", "res://testscroll.tscn", "res://distortions.tscn", "res://control.tscn"]
-scripts=["res://scenes/Nodes/scatter_value.gd", "res://scenes/Nodes/focus_accu_sliders.gd", "res://config_handler.gd", "res://Global.gd", "res://addons/audio_preview/AudioStreamPreview.gd", "res://addons/GDScriptAudioImport-master/README.md", "res://addons/GDScriptAudioImport-master/GDScriptAudioImport.gd", "res://addons/audio_preview/voice_preview_generator.gd", "res://scenes/Nodes/waveform_preview.gd", "res://scenes/Nodes/audioplayer.gd"]
+scripts=["res://export_presets.cfg", "res://scenes/Nodes/scatter_value.gd", "res://scenes/Nodes/focus_accu_sliders.gd", "res://config_handler.gd", "res://Global.gd", "res://addons/audio_preview/AudioStreamPreview.gd", "res://addons/GDScriptAudioImport-master/README.md", "res://addons/GDScriptAudioImport-master/GDScriptAudioImport.gd", "res://addons/audio_preview/voice_preview_generator.gd", "res://scenes/Nodes/waveform_preview.gd"]
 
 [script_setup]
 
@@ -25,7 +25,7 @@ embed_size_mode=2
 [color_picker]
 
 picker_shape=3
-recent_presets=PackedColorArray(0.184314, 0.309804, 0.305882, 1, 1, 1, 1, 0.541176, 1, 0, 1, 1, 0.59819, 0.558522, 0.969966, 1, 0.457908, 0.359424, 0.913417, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0.184314, 0.309804, 0.305882, 1)
+recent_presets=PackedColorArray(0.184314, 0.309804, 0.305882, 1, 1, 1, 1, 0.541176, 1, 0, 1, 1, 0.59819, 0.558522, 0.969966, 1, 0.457908, 0.359424, 0.913417, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0.184314, 0.309804, 0.305882, 1, 0.0962047, 0.0962048, 0.0962047, 1)
 
 [quick_open_dialog]
 

+ 29 - 11
.godot/editor/script_editor_cache.cfg

@@ -3,11 +3,11 @@
 state={
 "bookmarks": PackedInt32Array(),
 "breakpoints": PackedInt32Array(),
-"column": 26,
-"folded_lines": Array[int]([94, 125, 148, 151, 154, 195, 198, 204]),
+"column": 4,
+"folded_lines": Array[int]([76, 81, 85, 90, 94, 110, 141, 166, 169, 172, 175, 213, 216, 270, 340, 346, 591, 601, 664, 740, 745, 749, 784, 832]),
 "h_scroll_position": 0,
-"row": 316,
-"scroll_position": 217.0,
+"row": 907,
+"scroll_position": 504.0,
 "selection": false,
 "syntax_highlighter": "GDScript"
 }
@@ -17,7 +17,7 @@ state={
 state={
 "bookmarks": PackedInt32Array(),
 "breakpoints": PackedInt32Array(),
-"column": 12,
+"column": 11,
 "folded_lines": Array[int]([]),
 "h_scroll_position": 0,
 "row": 6,
@@ -52,9 +52,13 @@ state={
 "column": 0,
 "folded_lines": Array[int]([]),
 "h_scroll_position": 0,
-"row": 111,
-"scroll_position": 0.0,
-"selection": false,
+"row": 15,
+"scroll_position": 36.0,
+"selection": true,
+"selection_from_column": 0,
+"selection_from_line": 15,
+"selection_to_column": 50,
+"selection_to_line": 17,
 "syntax_highlighter": "GDScript"
 }
 
@@ -127,11 +131,11 @@ state={
 state={
 "bookmarks": PackedInt32Array(),
 "breakpoints": PackedInt32Array(),
-"column": 25,
+"column": 60,
 "folded_lines": Array[int]([]),
 "h_scroll_position": 0,
-"row": 21,
-"scroll_position": 0.0,
+"row": 9,
+"scroll_position": 9.0,
 "selection": false,
 "syntax_highlighter": "GDScript"
 }
@@ -163,3 +167,17 @@ state={
 "selection": false,
 "syntax_highlighter": "GDScript"
 }
+
+[res://export_presets.cfg]
+
+state={
+"bookmarks": PackedInt32Array(),
+"breakpoints": PackedInt32Array(),
+"column": 0,
+"folded_lines": Array[int]([]),
+"h_scroll_position": 0,
+"row": 0,
+"scroll_position": 0.0,
+"selection": false,
+"syntax_highlighter": "Plain Text"
+}

+ 1 - 1
.godot/editor/valueslider.tscn-editstate-d535ab38e866eae88d73c3fd55232f95.cfg

@@ -192,4 +192,4 @@ Game={
 "hide_selection": false,
 "select_mode": 0
 }
-selected_nodes=Array[NodePath]([NodePath("/root/@EditorNode@21272/@Panel@14/@VBoxContainer@15/DockHSplitLeftL/DockHSplitLeftR/DockHSplitMain/@VBoxContainer@26/DockVSplitCenter/@VSplitContainer@54/@VBoxContainer@55/@EditorMainScreen@102/MainScreen/@CanvasItemEditor@11482/@VSplitContainer@11134/@HSplitContainer@11136/@HSplitContainer@11138/@Control@11139/@SubViewportContainer@11140/@SubViewport@11141/Control")])
+selected_nodes=Array[NodePath]([NodePath("/root/@EditorNode@21272/@Panel@14/@VBoxContainer@15/DockHSplitLeftL/DockHSplitLeftR/DockHSplitMain/@VBoxContainer@26/DockVSplitCenter/@VSplitContainer@54/@VBoxContainer@55/@EditorMainScreen@102/MainScreen/@CanvasItemEditor@11482/@VSplitContainer@11134/@HSplitContainer@11136/@HSplitContainer@11138/@Control@11139/@SubViewportContainer@11140/@SubViewport@11141/Control/MenuBar/HelpButton")])

BIN
.godot/uid_cache.bin


+ 3 - 0
NodeData.tres

@@ -0,0 +1,3 @@
+[gd_resource type="Resource" format=3 uid="uid://diuumxgfvfyb6"]
+
+[resource]

+ 12 - 0
config_handler.gd

@@ -6,6 +6,8 @@ const SETTINGS_FILE_PATH = "user://settings.ini"
 func _ready():
 	if !FileAccess.file_exists(SETTINGS_FILE_PATH):
 		config.set_value("cdpprogs", "location", "no_location")
+		config.set_value("interface_settings", "disable_pvoc_warning", false)
+		config.set_value("interface_settings", "auto_close_console", false)
 		config.save(SETTINGS_FILE_PATH)
 	else:
 		config.load(SETTINGS_FILE_PATH)
@@ -20,3 +22,13 @@ func load_cdpprogs_settings():
 	for key in config.get_section_keys("cdpprogs"):
 		cdpprogs_settings[key] = config.get_value("cdpprogs", key)
 	return cdpprogs_settings
+
+func save_interface_settings(key: String, value):
+	config.set_value("interface_settings", key, value)
+	config.save(SETTINGS_FILE_PATH)
+
+func load_interface_settings():
+	var interface_settings = {}
+	for key in config.get_section_keys("interface_settings"):
+		interface_settings[key] = config.get_value("interface_settings", key)
+	return interface_settings

+ 236 - 0
examples/frequency_domain.thd

@@ -0,0 +1,236 @@
+{
+	"connections": [
+		{
+			"from_node": "inputfile",
+			"from_port": 0,
+			"to_node": "pvoc_anal_1",
+			"to_port": 0
+		},
+		{
+			"from_node": "spectstr_stretch",
+			"from_port": 0,
+			"to_node": "blur_blur",
+			"to_port": 0
+		},
+		{
+			"from_node": "pvoc_anal_1",
+			"from_port": 0,
+			"to_node": "spectstr_stretch",
+			"to_port": 0
+		},
+		{
+			"from_node": "pvoc_synth",
+			"from_port": 0,
+			"to_node": "outputfile",
+			"to_port": 0
+		},
+		{
+			"from_node": "blur_blur",
+			"from_port": 0,
+			"to_node": "pvoc_synth2",
+			"to_port": 0
+		},
+		{
+			"from_node": "pvoc_synth2",
+			"from_port": 0,
+			"to_node": "outputfile",
+			"to_port": 0
+		},
+		{
+			"from_node": "spectstr_stretch",
+			"from_port": 0,
+			"to_node": "blur_scatter",
+			"to_port": 0
+		},
+		{
+			"from_node": "blur_scatter",
+			"from_port": 0,
+			"to_node": "pvoc_synth",
+			"to_port": 0
+		}
+	],
+	"nodes": [
+		{
+			"command": "spectstr_stretch",
+			"name": "spectstr_stretch",
+			"notes": {
+
+			},
+			"offset": {
+				"x": 815.333312988281,
+				"y": 78.7777404785156
+			},
+			"slider_values": {
+				"HSlider": 0.0
+			}
+		},
+		{
+			"command": "blur_blur",
+			"name": "blur_blur",
+			"notes": {
+
+			},
+			"offset": {
+				"x": 1150.88891601563,
+				"y": 232.999954223633
+			},
+			"slider_values": {
+				"HSlider": 369.0
+			}
+		},
+		{
+			"command": "pvoc_synth",
+			"name": "pvoc_synth",
+			"notes": {
+
+			},
+			"offset": {
+				"x": 1477.66662597656,
+				"y": 79.2222137451172
+			},
+			"slider_values": {
+
+			}
+		},
+		{
+			"command": "pvoc_synth",
+			"name": "pvoc_synth2",
+			"notes": {
+
+			},
+			"offset": {
+				"x": 1478.77783203125,
+				"y": 232.666625976563
+			},
+			"slider_values": {
+
+			}
+		},
+		{
+			"command": "pvoc_anal_1",
+			"name": "pvoc_anal_1",
+			"notes": {
+
+			},
+			"offset": {
+				"x": 484.0,
+				"y": 78.3333358764648
+			},
+			"slider_values": {
+
+			}
+		},
+		{
+			"command": "outputfile",
+			"name": "outputfile",
+			"notes": {
+
+			},
+			"offset": {
+				"x": 1832.22229003906,
+				"y": 77.7777786254883
+			},
+			"slider_values": {
+				"@HSlider@1026": 0.0
+			}
+		},
+		{
+			"command": "notes",
+			"name": "notes",
+			"notes": {
+				"CodeEdit": "The \"Frequency Domain\" processes allow you to perform unique transformations to a sound"
+			},
+			"offset": {
+				"x": 64.6666793823242,
+				"y": 453.555572509766
+			},
+			"slider_values": {
+
+			}
+		},
+		{
+			"command": "notes",
+			"name": "notes2",
+			"notes": {
+				"CodeEdit": "These processes work by manipulating FFT analysis files of the audio and as such your audio must first be analysed using PVOC: Analyse"
+			},
+			"offset": {
+				"x": 483.444427490234,
+				"y": 454.333343505859
+			},
+			"slider_values": {
+
+			}
+		},
+		{
+			"command": "notes",
+			"name": "notes3",
+			"notes": {
+				"CodeEdit": "This enables processing that is difficult/impossible to do in the time domain. E.g. PVOC: Stretch allows extreme time stretching without changing pitch"
+			},
+			"offset": {
+				"x": 815.666687011719,
+				"y": 452.222229003906
+			},
+			"slider_values": {
+
+			}
+		},
+		{
+			"command": "notes",
+			"name": "notes4",
+			"notes": {
+				"CodeEdit": "Frequency Domain PVOC signals can be split but they cannot be mixed directly, if you want to mix the signals you will need to convert them back..."
+			},
+			"offset": {
+				"x": 1151.33337402344,
+				"y": 449.888885498047
+			},
+			"slider_values": {
+
+			}
+		},
+		{
+			"command": "notes",
+			"name": "notes5",
+			"notes": {
+				"CodeEdit": "...using PVOC: Resynthesise. This  process will take the analysis files that PVOC uses and turn it back into audio."
+			},
+			"offset": {
+				"x": 1481.55554199219,
+				"y": 449.666656494141
+			},
+			"slider_values": {
+
+			}
+		},
+		{
+			"command": "inputfile",
+			"name": "inputfile",
+			"notes": {
+
+			},
+			"offset": {
+				"x": 18.8888874053955,
+				"y": 78.8888854980469
+			},
+			"slider_values": {
+				"@HSlider@918": 0.0
+			}
+		},
+		{
+			"command": "blur_scatter",
+			"name": "blur_scatter",
+			"notes": {
+
+			},
+			"offset": {
+				"x": 1149.55541992188,
+				"y": 79.8888244628906
+			},
+			"slider_values": {
+				"HSlider": 16.0
+			}
+		}
+	]
+}

+ 3 - 2
project.godot

@@ -26,10 +26,11 @@ ConfigHandler="*res://config_handler.gd"
 
 [display]
 
+window/size/viewport_width=1280
+window/size/viewport_height=720
 window/size/mode=2
 window/subwindows/embed_subwindows=false
-window/stretch/mode="canvas_items"
-window/stretch/aspect="expand"
+window/stretch/aspect="ignore"
 
 [input]
 

+ 3 - 2
scenes/Nodes/nodes.tscn

@@ -38,6 +38,7 @@ slot/1/right_type = 0
 slot/1/right_color = Color(1, 1, 1, 1)
 slot/1/right_icon = null
 slot/1/draw_stylebox = true
+metadata/command = "inputfile"
 
 [node name="Control" type="Control" parent="inputfile"]
 layout_mode = 2
@@ -98,6 +99,7 @@ slot/4/right_type = 0
 slot/4/right_color = Color(1, 1, 1, 1)
 slot/4/right_icon = null
 slot/4/draw_stylebox = true
+metadata/command = "outputfile"
 
 [node name="Control" type="Control" parent="outputfile"]
 layout_mode = 2
@@ -1818,7 +1820,6 @@ offset_left = 1042.0
 offset_top = 32.0
 offset_right = 1348.0
 offset_bottom = 237.0
-tooltip_text = "Oscillate between harmonic and inharmonic state"
 title = "Notes"
 slot/0/left_enabled = false
 slot/0/left_type = 1
@@ -1829,7 +1830,7 @@ slot/0/right_type = 1
 slot/0/right_color = Color(0, 0, 0, 1)
 slot/0/right_icon = null
 slot/0/draw_stylebox = true
-metadata/command = "strange_waver_1"
+metadata/command = "notes"
 
 [node name="CodeEdit" type="CodeEdit" parent="notes"]
 custom_minimum_size = Vector2(0, 150)

+ 202 - 8
scenes/main/control.gd

@@ -21,6 +21,14 @@ func _ready() -> void:
 	$NoInputPopup.hide()
 	$MultipleConnectionsPopup.hide()
 	
+	$SaveDialog.access = FileDialog.ACCESS_FILESYSTEM
+	$SaveDialog.file_mode = FileDialog.FILE_MODE_SAVE_FILE
+	$SaveDialog.filters = ["*.thd"]
+	
+	$LoadDialog.access = FileDialog.ACCESS_FILESYSTEM
+	$LoadDialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE
+	$LoadDialog.filters = ["*.thd"]
+	
 	#Goes through all nodes in scene and checks for buttons in the make_node_buttons group
 	#Associates all buttons with the _on_button_pressed fuction and passes the button as an argument
 	for child in get_tree().get_nodes_in_group("make_node_buttons"):
@@ -30,13 +38,15 @@ func _ready() -> void:
 	#Generate input and output nodes
 	var effect: GraphNode = Nodes.get_node(NodePath("inputfile")).duplicate()
 	get_node("GraphEdit").add_child(effect, true)
-	effect.position_offset = Vector2(-500,-150)
+	effect.position_offset = Vector2(20,80)
 	
 	effect = Nodes.get_node(NodePath("outputfile")).duplicate()
 	get_node("GraphEdit").add_child(effect, true)
-	effect.position_offset = Vector2(1000,-150)
+	effect.position_offset = Vector2(1400,80)
 	
 	check_cdp_location_set()
+	check_user_preferences()
+	
 	
 	#link output file to input file to enable audio output file loopback
 	$GraphEdit/outputfile/AudioPlayer.recycle_outfile_trigger.connect($GraphEdit/inputfile/AudioPlayer.recycle_outfile)
@@ -48,6 +58,12 @@ func _ready() -> void:
 	$GraphEdit/outputfile/DeleteIntermediateFilesToggle.toggled.connect(_toggle_delete)
 	$GraphEdit/outputfile/DeleteIntermediateFilesToggle.button_pressed = true
 	
+func check_user_preferences():
+	var interface_settings = ConfigHandler.load_interface_settings()
+	$MenuBar/SettingsButton.set_item_checked(1, interface_settings.disable_pvoc_warning)
+	$MenuBar/SettingsButton.set_item_checked(2, interface_settings.auto_close_console)
+
+	
 func check_cdp_location_set():
 	#checks if the location has been set and prompts user to set it
 	var cdpprogs_settings = ConfigHandler.load_cdpprogs_settings()
@@ -140,7 +156,9 @@ func _on_graph_edit_connection_request(from_node: StringName, from_port: int, to
 			if conn.to_node == to_node and conn.to_port == to_port:
 				existing_connections += 1
 				if existing_connections >= 1:
-					$MultipleConnectionsPopup.show()
+					var interface_settings = ConfigHandler.load_interface_settings()
+					if interface_settings.disable_pvoc_warning == false:
+						$MultipleConnectionsPopup.show()
 					return
 
 	# If no conflict, allow the connection
@@ -230,7 +248,6 @@ func copy_selected_nodes():
 
 	# Store connections between selected nodes
 	for conn in graph_edit.get_connection_list():
-		# Assuming 'from_node' and 'to_node' are StringName values
 		var from_ref = graph_edit.get_node_or_null(NodePath(conn["from_node"]))
 		var to_ref = graph_edit.get_node_or_null(NodePath(conn["to_node"]))
 
@@ -316,7 +333,9 @@ func paste_copied_nodes():
 		undo_redo.add_undo_method(Callable(self, "remove_connections_to_node").bind(pasted_node))
 	undo_redo.commit_action()
 
-#Here be dragons
+######## Here be dragons #########
+##################################
+
 #Scans through all nodes and generates a batch file based on their order
 
 func _run_process() -> void:
@@ -328,7 +347,9 @@ func _run_process() -> void:
 func _on_file_dialog_dir_selected(dir: String) -> void:
 	console_output.clear()
 	$Console.show()
+	await get_tree().process_frame
 	log_console("Generating processing queue", true)
+	await get_tree().process_frame
 
 	#get the current time in hh-mm-ss format as default : causes file name issues
 	var time_dict = Time.get_time_dict_from_system()
@@ -339,6 +360,7 @@ func _on_file_dialog_dir_selected(dir: String) -> void:
 	var time_str = hour + "-" + minute + "-" + second
 	Global.outfile = dir + "/outfile_" + Time.get_date_string_from_system() + "_" + time_str
 	log_console("Output directory and file name(s):" + Global.outfile, true)
+	await get_tree().process_frame
 	
 	generate_batch_file_with_branches()
 	
@@ -348,7 +370,10 @@ func generate_batch_file_with_branches():
 	var reverse_graph = {}
 	var indegree = {}
 	var all_nodes = {}
-
+	
+	log_console("Generating batch file.", true)
+	await get_tree().process_frame
+	
 	# Step 1: Collect nodes
 	for child in graph_edit.get_children():
 		if child is GraphNode:
@@ -391,6 +416,9 @@ func generate_batch_file_with_branches():
 	var stereo_outputs = {}
 
 	if Global.infile_stereo:
+		log_console("Input file is stereo, note this may cause left/right decorrelation with some processes.", true)
+		await get_tree().process_frame
+		
 		# Step 4.1: Split stereo to c1/c2
 		batch_lines.append("%s/housekeep chans 2 \"%s\"" % [cdpprogs_location, Global.infile])
 
@@ -544,7 +572,7 @@ func generate_batch_file_with_branches():
 			intermediate_files.erase(single_output)
 
 		# Step 5: Cleanup commands
-		log_console("Adding cleanup commands for intermediate files", true)
+		log_console("Adding cleanup commands for intermediate files.", true)
 		for file_path in intermediate_files:
 			batch_lines.append("del \"%s\"" % file_path.replace("/", "\\"))
 
@@ -554,7 +582,9 @@ func generate_batch_file_with_branches():
 		file.store_line(line)
 	file.close()
 
-	log_console("Batch script with merging written.", true)
+	log_console("Batch file complete.", true)
+	log_console("Processing audio, please wait.", true)
+	await get_tree().process_frame
 	run_batch_file()
 
 
@@ -684,12 +714,16 @@ func run_batch_file():
 		console_output.append_text(output_str + "/n")
 		if final_output_dir.ends_with(".wav"):
 			$GraphEdit/outputfile/AudioPlayer.play_outfile(final_output_dir)
+		var interface_settings = ConfigHandler.load_interface_settings()
+		if interface_settings.auto_close_console == true:
+			$Console.hide()
 	else:
 		console_output.append_text("[color=red][b]Processes failed with exit code: %d[/b][/color]\n" % exit_code + "\n \n")
 		console_output.append_text("[b]Error:[/b]\n" )
 		console_output.scroll_to_line(console_output.get_line_count() - 1)
 		console_output.append_text(error_str + "/n")
 
+######## Realtively free from dragons from here
 
 func _toggle_delete(toggled_on: bool):
 	delete_intermediate_outputs = toggled_on
@@ -715,3 +749,163 @@ func _on_ok_button_2_button_down() -> void:
 
 func _on_ok_button_3_button_down() -> void:
 	$MultipleConnectionsPopup.hide()
+
+
+
+func _on_settings_button_index_pressed(index: int) -> void:
+	var interface_settings = ConfigHandler.load_interface_settings()
+	
+	match index:
+		0:
+			$CdpLocationDialog.show()
+		1:
+			if interface_settings.disable_pvoc_warning == false:
+				$MenuBar/SettingsButton.set_item_checked(index, true)
+				ConfigHandler.save_interface_settings("disable_pvoc_warning", true)
+			else:
+				$MenuBar/SettingsButton.set_item_checked(index, false)
+				ConfigHandler.save_interface_settings("disable_pvoc_warning", false)
+		2:
+			if interface_settings.auto_close_console == false:
+				$MenuBar/SettingsButton.set_item_checked(index, true)
+				ConfigHandler.save_interface_settings("auto_close_console", true)
+			else:
+				$MenuBar/SettingsButton.set_item_checked(index, false)
+				ConfigHandler.save_interface_settings("auto_close_console", false)
+
+
+func _on_file_button_index_pressed(index: int) -> void:
+	match index:
+		0:
+			$SaveDialog.popup_centered()
+		1:
+			$LoadDialog.popup_centered()
+
+
+func save_graph_edit(path: String):
+	var file = FileAccess.open(path, FileAccess.WRITE)
+	if file == null:
+		print("Failed to open file for saving")
+		return
+
+	var node_data_list = []
+	var connection_data_list = []
+
+	for node in graph_edit.get_children():
+		if node is GraphNode:
+			var offset = node.position_offset
+			var node_data = {
+				"name": node.name,
+				"command": node.get_meta("command"),
+				"offset": { "x": offset.x, "y": offset.y },
+				"slider_values": {},
+				"notes":{}
+			}
+
+			for child in node.find_children("*", "Slider", true, false):
+				node_data["slider_values"][child.name] = child.value
+				
+			for child in node.find_children("*", "CodeEdit", true, false):
+				node_data["notes"][child.name] = child.text
+
+			node_data_list.append(node_data)
+
+	for conn in graph_edit.get_connection_list():
+		connection_data_list.append({
+			"from_node": conn["from_node"],
+			"from_port": conn["from_port"],
+			"to_node": conn["to_node"],
+			"to_port": conn["to_port"]
+		})
+
+	var graph_data = {
+		"nodes": node_data_list,
+		"connections": connection_data_list
+	}
+
+	var json = JSON.new()
+	var json_string = json.stringify(graph_data, "\t")
+	file.store_string(json_string)
+	file.close()
+	print("Graph saved.")
+
+
+func load_graph_edit(path: String):
+	var file = FileAccess.open(path, FileAccess.READ)
+	if file == null:
+		print("Failed to open file for loading")
+		return
+
+	var json_text = file.get_as_text()
+	file.close()
+
+	var json = JSON.new()
+	if json.parse(json_text) != OK:
+		print("Error parsing JSON")
+		return
+
+	var graph_data = json.get_data()
+	graph_edit.clear_connections()
+
+	for node in graph_edit.get_children():
+		if node is GraphNode:
+			node.queue_free()
+
+	await get_tree().process_frame  # Ensure nodes are cleared
+
+	for node_data in graph_data["nodes"]:
+		var command_name = node_data.get("command", "")
+		var template = Nodes.get_node_or_null(command_name)
+		if not template:
+			print("Template not found for command:", command_name)
+			continue
+
+		var new_node: GraphNode = template.duplicate()
+		new_node.name = node_data["name"]
+		new_node.position_offset = Vector2(node_data["offset"]["x"], node_data["offset"]["y"])
+		new_node.set_meta("command", command_name)
+		graph_edit.add_child(new_node)
+
+		# Restore sliders
+		for slider_name in node_data["slider_values"]:
+			var slider = new_node.find_child(slider_name, true, false)
+			if slider and (slider is HSlider or slider is VSlider):
+				slider.value = node_data["slider_values"][slider_name]
+				
+		# Restore notes
+		for codeedit_name in node_data["notes"]:
+			var codeedit = new_node.find_child(codeedit_name, true, false)
+			if codeedit and (codeedit is CodeEdit):
+				codeedit.text = node_data["notes"][codeedit_name]
+			
+	# Restore connections
+	for conn in graph_data["connections"]:
+		graph_edit.connect_node(
+			conn["from_node"], conn["from_port"],
+			conn["to_node"], conn["to_port"]
+		)
+
+	print("Graph loaded.")
+
+
+func _on_save_dialog_file_selected(path: String) -> void:
+	save_graph_edit(path)
+
+
+
+func _on_load_dialog_file_selected(path: String) -> void:
+	load_graph_edit(path)
+
+
+func _on_help_button_index_pressed(index: int) -> void:
+	match index:
+		0:
+			pass
+		1:
+			pass
+		2:
+			load_graph_edit("res://examples/frequency_domain.thd")
+		3:
+			pass
+		4:
+			OS.shell_open("https://www.composersdesktop.com/docs/html/cdphome.htm")

+ 69 - 1
scenes/main/control.tscn

@@ -18,6 +18,7 @@ layout_mode = 1
 anchors_preset = -1
 anchor_right = 1.0
 anchor_bottom = 1.0
+offset_top = 32.0
 right_disconnects = true
 script = ExtResource("2_3ioqo")
 
@@ -30,6 +31,7 @@ use_native_dialog = true
 
 [node name="mainmenu" parent="." instance=ExtResource("3_dtf4o")]
 layout_mode = 1
+offset_top = 32.0
 
 [node name="NoLocationPopup" type="Window" parent="."]
 auto_translate_mode = 1
@@ -135,7 +137,6 @@ use_native_dialog = true
 title = "Generating Output"
 initial_position = 5
 size = Vector2i(600, 400)
-visible = false
 unresizable = true
 always_on_top = true
 
@@ -159,6 +160,68 @@ offset_right = 428.0
 offset_bottom = 389.0
 text = "Open Output Folder"
 
+[node name="ColorRect" type="ColorRect" parent="."]
+layout_mode = 1
+anchors_preset = 10
+anchor_right = 1.0
+offset_bottom = 32.0
+grow_horizontal = 2
+color = Color(0.054902, 0.0745098, 0.0745098, 1)
+
+[node name="MenuBar" type="MenuBar" parent="."]
+layout_mode = 1
+anchors_preset = 10
+anchor_right = 1.0
+offset_left = 8.0
+offset_right = -8.0
+offset_bottom = 31.0
+grow_horizontal = 2
+flat = true
+
+[node name="FileButton" type="PopupMenu" parent="MenuBar"]
+title = "File"
+item_count = 2
+item_0/text = "Save Process Chain"
+item_0/id = 0
+item_1/text = "Load Process Chain"
+item_1/id = 1
+
+[node name="SettingsButton" type="PopupMenu" parent="MenuBar"]
+title = "Settings"
+item_count = 3
+item_0/text = "Change CDP Folder Location"
+item_0/id = 0
+item_1/text = "Disable PVOC Multi Input Warning"
+item_1/checkable = 1
+item_1/id = 1
+item_2/text = "Auto Close Console"
+item_2/checkable = 1
+item_2/id = 2
+
+[node name="HelpButton" type="PopupMenu" parent="MenuBar"]
+auto_translate_mode = 1
+title = "Help"
+item_count = 5
+item_0/text = "Demos"
+item_0/id = 0
+item_0/separator = true
+item_1/text = "Combining Nodes"
+item_1/id = 2
+item_2/text = "Frequency Domain"
+item_2/id = 2
+item_3/text = "Other Help"
+item_3/id = 3
+item_3/separator = true
+item_4/text = "CDP Documentation"
+item_4/id = 4
+
+[node name="SaveDialog" type="FileDialog" parent="."]
+use_native_dialog = true
+
+[node name="LoadDialog" type="FileDialog" parent="."]
+auto_translate_mode = 1
+use_native_dialog = true
+
 [connection signal="connection_request" from="GraphEdit" to="." method="_on_graph_edit_connection_request"]
 [connection signal="delete_nodes_request" from="GraphEdit" to="." method="_on_graph_edit_delete_nodes_request"]
 [connection signal="disconnection_request" from="GraphEdit" to="." method="_on_graph_edit_disconnection_request"]
@@ -172,3 +235,8 @@ text = "Open Output Folder"
 [connection signal="dir_selected" from="CdpLocationDialog" to="." method="_on_cdp_location_dialog_dir_selected"]
 [connection signal="close_requested" from="Console" to="." method="_on_console_close_requested"]
 [connection signal="button_down" from="Console/ConsoleOpenFolder" to="." method="_on_console_open_folder_button_down"]
+[connection signal="index_pressed" from="MenuBar/FileButton" to="." method="_on_file_button_index_pressed"]
+[connection signal="index_pressed" from="MenuBar/SettingsButton" to="." method="_on_settings_button_index_pressed"]
+[connection signal="index_pressed" from="MenuBar/HelpButton" to="." method="_on_help_button_index_pressed"]
+[connection signal="file_selected" from="SaveDialog" to="." method="_on_save_dialog_file_selected"]
+[connection signal="file_selected" from="LoadDialog" to="." method="_on_load_dialog_file_selected"]

+ 1 - 1
scenes/main/graph_edit.gd

@@ -4,4 +4,4 @@ extends GraphEdit
 func _ready() -> void:
 	snapping_enabled = false
 	show_grid = false
-	zoom = 0.55
+	zoom = 0.9

Some files were not shown because too many files changed in this diff