diff --git a/GdpdExample/Main.tscn b/GdpdExample/Main.tscn index f71fe75..3889266 100644 --- a/GdpdExample/Main.tscn +++ b/GdpdExample/Main.tscn @@ -1,110 +1,70 @@ -[gd_scene load_steps=2 format=2] +[gd_scene load_steps=5 format=2] -[sub_resource type="GDScript" id=1] -script/source = "extends Control +[ext_resource path="res://main.gd" type="Script" id=1] -var _gdpd -var _patches = [] +[sub_resource type="PhysicsMaterial" id=3] -func _load_patch(pd_patch) : - #separate file name from directory - var patch_name = pd_patch.split(\"/\")[-1] - var patch_dir = pd_patch.trim_suffix(patch_name) +[sub_resource type="SphereShape" id=1] - #load patch - var id = _gdpd.openPatch(patch_name, patch_dir) - _patches.append(id) -# print(\"loading:\" + str(id)) - -func _ready() : - _gdpd = load(\"res://addons/gdpd/bin/gdpd.gdns\").new() - -func _process(delta) : - while _gdpd.has_message() : - var msg = _gdpd.get_next() - print(msg) - if msg[0] == \"random\" : -# print(\"r\") - pass - -func _on_Start_pressed() : - var inps = _gdpd.get_available_input_devices() - var outs = _gdpd.get_available_output_devices() -# _gdpd.init(0, 2, 48000, 64) - _gdpd.init_devices(inps[0], outs[0]) - - #the patch path should be the absolute one - _load_patch(ProjectSettings.globalize_path(\"res://patch.pd\")) - _load_patch(ProjectSettings.globalize_path(\"res://patch.pd\")) - _load_patch(ProjectSettings.globalize_path(\"res://patch.pd\")) - _load_patch(ProjectSettings.globalize_path(\"res://patch.pd\")) - _load_patch(ProjectSettings.globalize_path(\"res://patch.pd\")) - _load_patch(ProjectSettings.globalize_path(\"res://patch.pd\")) - _load_patch(ProjectSettings.globalize_path(\"res://patch.pd\")) - _load_patch(ProjectSettings.globalize_path(\"res://patch.pd\")) - _load_patch(ProjectSettings.globalize_path(\"res://patch.pd\")) - _load_patch(ProjectSettings.globalize_path(\"res://patch.pd\")) - - _gdpd.subscribe(\"toGodot\") - -func _on_Stop_pressed() : - print(_patches) - for id in _patches: -# print(\"closing:\" + str(id)) - _gdpd.closePatch(id) - # _patches.erase(id) # <= BAD! - # Do not erase entries while iterating over the array !! - _patches.clear() - _gdpd.stop() - -func _on_Send_pressed() : - _gdpd.start_message(1) - _gdpd.add_float(300) - _gdpd.finish_list(\"fromGodot\") +[sub_resource type="SphereMesh" id=2] +resource_local_to_scene = true +[node name="main" type="RigidBody" groups=["sounders"]] +collision_layer = 4 +collision_mask = 0 +physics_material_override = SubResource( 3 ) +gravity_scale = 0.0 +script = ExtResource( 1 ) +patch = "#N canvas 574 271 456 518 12; +#X obj 361 21 loadbang; +#X msg 361 51 \\; pd dsp 1; +#X floatatom 21 198 5 0 0 0 - - - 0; +#X obj 21 22 r fromGodot\\$0; +#X obj 21 46 list trim; +#X obj 199 467 dac~ 1 2; +#X obj 199 407 *~; +#X obj 189 230 line~; +#X msg 189 206 \\$1 100; +#X obj 189 127 unpack f f; +#X floatatom 189 177 5 0 0 0 - - - 0; +#X obj 21 256 noise~; +#X obj 21 286 bp~ 500 1000; +#X obj 21 70 route freq gain panvol; +#X obj 21 316 *~; +#X msg 296 338 \\$1 100; +#X floatatom 296 159 5 0 0 0 - - - 0; +#X obj 199 437 earplug~ 0 0; +#X obj 296 362 line; +#X obj 122 158 != 0; +#X obj 122 206 switch~; +#X obj 122 182 tgl 19 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X connect 2 0 12 1; +#X connect 3 0 4 0; +#X connect 4 0 13 0; +#X connect 6 0 17 0; +#X connect 7 0 6 1; +#X connect 8 0 7 0; +#X connect 9 0 10 0; +#X connect 9 1 16 0; +#X connect 10 0 8 0; +#X connect 10 0 19 0; +#X connect 11 0 12 0; +#X connect 12 0 14 0; +#X connect 13 0 2 0; +#X connect 13 1 14 1; +#X connect 13 2 9 0; +#X connect 14 0 6 0; +#X connect 15 0 18 0; +#X connect 16 0 15 0; +#X connect 17 0 5 0; +#X connect 17 1 5 1; +#X connect 18 0 17 1; +#X connect 19 0 21 0; +#X connect 21 0 20 0; " -[node name="Control" type="Control"] -anchor_right = 1.0 -anchor_bottom = 1.0 -script = SubResource( 1 ) -__meta__ = { -"_edit_use_anchors_": false -} +[node name="CollisionShape" type="CollisionShape" parent="."] +shape = SubResource( 1 ) -[node name="Stop" type="Button" parent="."] -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -margin_left = -50.0 -margin_top = 75.0 -margin_right = 50.0 -margin_bottom = 125.0 -text = "Stop" - -[node name="Start" type="Button" parent="."] -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -margin_left = -50.0 -margin_top = -125.0 -margin_right = 50.0 -margin_bottom = -75.0 -text = "Start" - -[node name="Send" type="Button" parent="."] -anchor_left = 0.5 -anchor_top = 0.5 -anchor_right = 0.5 -anchor_bottom = 0.5 -margin_left = -50.0 -margin_top = -25.0 -margin_right = 50.0 -margin_bottom = 25.0 -text = "send" - -[connection signal="pressed" from="Stop" to="." method="_on_Stop_pressed"] -[connection signal="pressed" from="Start" to="." method="_on_Start_pressed"] -[connection signal="pressed" from="Send" to="." method="_on_Send_pressed"] +[node name="MeshInstance" type="MeshInstance" parent="."] +mesh = SubResource( 2 ) diff --git a/GdpdExample/Player.gd b/GdpdExample/Player.gd new file mode 100644 index 0000000..3a5c148 --- /dev/null +++ b/GdpdExample/Player.gd @@ -0,0 +1,78 @@ +extends KinematicBody + +var camera_angle = 0 +var mouse_sensitivity = 0.3 +var camera_change = Vector2() + +var velocity = Vector3() +var direction = Vector3() + +#fly variables +const FLY_SPEED = 20 +const FLY_ACCEL = 4 + +var mouse_captured = true + +func _ready(): + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) + +func _physics_process(delta): + + if mouse_captured: + aim() + fly(delta) + # emit signal - playerinfo_updated + var tf = $Head/Camera.get_global_transform_interpolated() + if tf != Events.player_tf_old: + Events.emit_signal("player_transform_updated", $Head/Camera.get_global_translation(), $Head.global_rotation.y) + Events.player_tf_old = tf + + if Input.is_action_just_pressed('toggle_mouse'): + if mouse_captured: + mouse_captured = false + Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) + else: + mouse_captured = true + Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) + +func _input(event): + if event is InputEventMouseMotion: + camera_change = event.relative + +func fly(delta): + # reset the direction of the player + direction = Vector3() + + # get the rotation of the camera + var aim = $Head/Camera.get_global_transform().basis + + # check input and change direction + if Input.is_action_pressed("move_forward"): + direction -= aim.z + if Input.is_action_pressed("move_backward"): + direction += aim.z + if Input.is_action_pressed("move_left"): + direction -= aim.x + if Input.is_action_pressed("move_right"): + direction += aim.x + + direction = direction.normalized() + + # where would the player go at max speed + var target = direction * FLY_SPEED + + # calculate a portion of the distance to go + velocity = velocity.linear_interpolate(target, FLY_ACCEL * delta) + + # move + move_and_slide(velocity) + +func aim(): + if camera_change.length() > 0: + $Head.rotate_y(deg2rad(-camera_change.x * mouse_sensitivity)) + + var change = -camera_change.y * mouse_sensitivity + if change + camera_angle < 90 and change + camera_angle > -90: + $Head/Camera.rotate_x(deg2rad(change)) + camera_angle += change + camera_change = Vector2() diff --git a/GdpdExample/Player.tscn b/GdpdExample/Player.tscn new file mode 100644 index 0000000..3900a7b --- /dev/null +++ b/GdpdExample/Player.tscn @@ -0,0 +1,21 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://Player.gd" type="Script" id=1] + +[sub_resource type="CapsuleShape" id=1] +radius = 0.6 +height = 2.0 + +[node name="Player" type="KinematicBody"] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3.52113, 0.98772 ) +script = ExtResource( 1 ) + +[node name="Capsule" type="CollisionShape" parent="."] +transform = Transform( 1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0 ) +shape = SubResource( 1 ) + +[node name="Head" type="Spatial" parent="."] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 0 ) + +[node name="Camera" type="Camera" parent="Head"] +far = 10000.0 diff --git a/GdpdExample/Region.gd b/GdpdExample/Region.gd new file mode 100644 index 0000000..6cce0f4 --- /dev/null +++ b/GdpdExample/Region.gd @@ -0,0 +1,24 @@ +extends Spatial + +var main = load("res://main.tscn") +var sub = load("res://osc.tscn") + +func _ready(): + # 'main' at center. + var m = main.instance() + add_child(m) + m.set_size(rand_range(10, 15)) + m.audible_range_max = 80 + m.set_freq(rand_range(100, 300)) + m.set_gain(40) + + # many 'sub' surrounds 'main' like satellites + for i in range(18): + var s = sub.instance() + add_child(s) + s.set_size(rand_range(0.2, 1.2)) + s.set_color(Color.black) + var d = polar2cartesian(rand_range(20, 24), rand_range(0, 2*PI)) + s.translate(Vector3(d.x, rand_range(-2, 2), d.y)) + s.set_freq(rand_range(200, 2000)) + s.set_gain(0.1) diff --git a/GdpdExample/Region.tscn b/GdpdExample/Region.tscn new file mode 100644 index 0000000..32efd0b --- /dev/null +++ b/GdpdExample/Region.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://Region.gd" type="Script" id=1] + +[node name="Region" type="Spatial"] +script = ExtResource( 1 ) diff --git a/GdpdExample/Scene.gd b/GdpdExample/Scene.gd new file mode 100644 index 0000000..8d16f4c --- /dev/null +++ b/GdpdExample/Scene.gd @@ -0,0 +1,11 @@ +extends Node + +#var region = load("res://Region.tscn") + +func _ready(): + pass +# for i in range(18): +# var oscnode = osctscn.instance() +# oscnode.set_size(randf()*5 + 0.2) +# oscnode.set_freq(randf()*800 + 200) +# add_child(oscnode) diff --git a/GdpdExample/Scene.tscn b/GdpdExample/Scene.tscn new file mode 100644 index 0000000..d6532e5 --- /dev/null +++ b/GdpdExample/Scene.tscn @@ -0,0 +1,44 @@ +[gd_scene load_steps=7 format=2] + +[ext_resource path="res://Region.tscn" type="PackedScene" id=1] +[ext_resource path="res://Player.tscn" type="PackedScene" id=2] +[ext_resource path="res://Scene.gd" type="Script" id=3] + +[sub_resource type="BoxShape" id=1] +extents = Vector3( 300, 1, 300 ) + +[sub_resource type="CubeMesh" id=2] +size = Vector3( 600, 2, 600 ) + +[sub_resource type="Environment" id=3] +fog_enabled = true + +[node name="Scene" type="Node"] +script = ExtResource( 3 ) + +[node name="StaticBody" type="StaticBody" parent="."] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0 ) + +[node name="CollisionShape" type="CollisionShape" parent="StaticBody"] +shape = SubResource( 1 ) + +[node name="MeshInstance" type="MeshInstance" parent="StaticBody"] +mesh = SubResource( 2 ) + +[node name="DirectionalLight" type="DirectionalLight" parent="."] +transform = Transform( 1, 0, 0, 0, 0.158589, 0.987345, 0, -0.987345, 0.158589, 0, 57.3999, 0 ) +shadow_enabled = true + +[node name="Player" parent="." instance=ExtResource( 2 )] + +[node name="WorldEnvironment" type="WorldEnvironment" parent="."] +environment = SubResource( 3 ) + +[node name="Region" parent="." instance=ExtResource( 1 )] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 30, 0 ) + +[node name="Region2" parent="." instance=ExtResource( 1 )] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -193.573, 78.9511, 112.625 ) + +[node name="Region3" parent="." instance=ExtResource( 1 )] +transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 67.7793, 64.9703, -27.1477 ) diff --git a/GdpdExample/addons/gdpd/bin/osx/libgdpd.dylib b/GdpdExample/addons/gdpd/bin/osx/libgdpd.dylib index f220301..a8021de 100755 Binary files a/GdpdExample/addons/gdpd/bin/osx/libgdpd.dylib and b/GdpdExample/addons/gdpd/bin/osx/libgdpd.dylib differ diff --git a/GdpdExample/autoload/Events.gd b/GdpdExample/autoload/Events.gd new file mode 100644 index 0000000..c50a795 --- /dev/null +++ b/GdpdExample/autoload/Events.gd @@ -0,0 +1,6 @@ +extends Node + +var player_tf_old = Transform() +signal player_transform_updated(position, heading) +# position : Vector3 +# heading : Vector2 (projected x-z plane, and normalized) diff --git a/GdpdExample/autoload/Events.tscn b/GdpdExample/autoload/Events.tscn new file mode 100644 index 0000000..00dabc1 --- /dev/null +++ b/GdpdExample/autoload/Events.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://autoload/Events.gd" type="Script" id=1] + +[node name="Events" type="Node"] +script = ExtResource( 1 ) diff --git a/GdpdExample/autoload/Global.gd b/GdpdExample/autoload/Global.gd new file mode 100644 index 0000000..f9b2265 --- /dev/null +++ b/GdpdExample/autoload/Global.gd @@ -0,0 +1,93 @@ +extends Node + + +#gdpd (pd interface with godot) +var _gdpd +var _patches = [] + +export (bool) var _enable_gui = false +export (String) var _gui_path = "/Applications/Pd-0.53-1.app/Contents/Resources" +export (bool) var _verbose = false +export (float) var _sample_rate = 48000 +export (int) var _blocksize = 256 + +func _ready(): + _gdpd = load("res://addons/gdpd/bin/gdpd.gdns").new() + if _enable_gui: + # set gui path to activate gui window (otherwise, nogui) + _gdpd.set_gui_path(_gui_path) + _gdpd.set_volume(1) # by default, volume(gain) == 0 + _gdpd.set_verbose(_verbose) # by default, suppress 'print' + _gdpd.init(0, 2, _sample_rate, _blocksize) + _gdpd.computeAudio(true) # [; pd dsp 1 ( + _gdpd.subscribe("toGodot") + # delayed 'stream start' to prevent start-up 'pop' noise. + yield(get_tree().create_timer(0.3), "timeout") + _gdpd.streamstart() + +func _exit_tree(): + if _patches.size() != 0: + print() + print("! ======== * purging leftover opened patches ... * ======== !") + print() + for id in _patches: + _gdpd.closePatch(id) + _patches.clear() + _gdpd.stop() + +func load_patch(pd_patch) -> int: + #the patch path should be the absolute one + #separate file name from directory + var patch_name = pd_patch.split("/")[-1] + var patch_dir = pd_patch.trim_suffix(patch_name) + var id = _gdpd.openPatch(patch_name, patch_dir) + _patches.append(id) + return id + +func close_patch(id): + if id in _patches: + _gdpd.closePatch(id) + _patches.erase(id) + +func _process(_delta) : + while _gdpd.has_message(): + var msg = _gdpd.get_next() + print(msg) +# if msg[0] == "random": +# print("r") + + + + + +# ==== archived. ==== + + + # duplicate "res://" into 'user://' ==> we need godot 4 for this approach.. +# _copydirectory_recursive("res://", "user://") + + +## copy directory recursively ==> we need godot 4 for this approach.. +#func _copydirectory_recursive(src, dst): +# var dotfolders = RegEx.new() +# dotfolders.compile("^\\.\\w*") +# var pdfiles = RegEx.new() +# pdfiles.compile("\\w+\\.pd$") +# var dir = Directory.new() +# if dir.open(src) == OK: +# dir.list_dir_begin() +# var file_name = dir.get_next() +# while file_name != "": +# if dir.current_is_dir(): +# print("Found directory: " + file_name) +# if not dotfolders.search(file_name): +# dir.make_dir(dst + "/" + file_name) +# _copydirectory_recursive(dir.get_current_dir() + "/" + file_name, dst + "/" + file_name) +# else: +# if pdfiles.search(file_name): +# print("Found puredata file: " + file_name) +# dir.copy(src + "/" + file_name, dst + "/" + file_name) +# +# file_name = dir.get_next() +# else: +# print("An error occurred when trying to access the path. : " + src) diff --git a/GdpdExample/autoload/Global.tscn b/GdpdExample/autoload/Global.tscn new file mode 100644 index 0000000..a00373d --- /dev/null +++ b/GdpdExample/autoload/Global.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://autoload/Global.gd" type="Script" id=1] + +[node name="Global" type="Node"] +script = ExtResource( 1 ) diff --git a/GdpdExample/export_presets.cfg b/GdpdExample/export_presets.cfg new file mode 100644 index 0000000..2d3b85b --- /dev/null +++ b/GdpdExample/export_presets.cfg @@ -0,0 +1,73 @@ +[preset.0] + +name="Mac OSX" +platform="Mac OSX" +runnable=true +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="./Sands and Waves (worldscene1).dmg" +script_export_mode=1 +script_encryption_key="" + +[preset.0.options] + +custom_template/debug="" +custom_template/release="" +application/name="" +application/info="Made with Godot Engine" +application/icon="" +application/identifier="in.dianaband.worldscene1" +application/signature="" +application/app_category="Games" +application/short_version="1.0" +application/version="1.0" +application/copyright="" +display/high_res=false +privacy/microphone_usage_description="" +privacy/camera_usage_description="" +privacy/location_usage_description="" +privacy/address_book_usage_description="" +privacy/calendar_usage_description="" +privacy/photos_library_usage_description="" +privacy/desktop_folder_usage_description="" +privacy/documents_folder_usage_description="" +privacy/downloads_folder_usage_description="" +privacy/network_volumes_usage_description="" +privacy/removable_volumes_usage_description="" +codesign/enable=true +codesign/identity="" +codesign/timestamp=false +codesign/hardened_runtime=false +codesign/replace_existing_signature=true +codesign/entitlements/custom_file="" +codesign/entitlements/allow_jit_code_execution=false +codesign/entitlements/allow_unsigned_executable_memory=false +codesign/entitlements/allow_dyld_environment_variables=false +codesign/entitlements/disable_library_validation=true +codesign/entitlements/audio_input=false +codesign/entitlements/camera=false +codesign/entitlements/location=false +codesign/entitlements/address_book=false +codesign/entitlements/calendars=false +codesign/entitlements/photos_library=false +codesign/entitlements/apple_events=false +codesign/entitlements/debugging=false +codesign/entitlements/app_sandbox/enabled=false +codesign/entitlements/app_sandbox/network_server=false +codesign/entitlements/app_sandbox/network_client=false +codesign/entitlements/app_sandbox/device_usb=false +codesign/entitlements/app_sandbox/device_bluetooth=false +codesign/entitlements/app_sandbox/files_downloads=0 +codesign/entitlements/app_sandbox/files_pictures=0 +codesign/entitlements/app_sandbox/files_music=0 +codesign/entitlements/app_sandbox/files_movies=0 +codesign/custom_options=PoolStringArray( ) +notarization/enable=false +notarization/apple_id_name="" +notarization/apple_id_password="" +notarization/apple_team_id="" +texture_format/s3tc=true +texture_format/etc=false +texture_format/etc2=false diff --git a/GdpdExample/icon.png b/GdpdExample/icon.png index 9f3f450..c98fbb6 100644 Binary files a/GdpdExample/icon.png and b/GdpdExample/icon.png differ diff --git a/GdpdExample/main.gd b/GdpdExample/main.gd new file mode 100644 index 0000000..4a61b26 --- /dev/null +++ b/GdpdExample/main.gd @@ -0,0 +1,82 @@ +extends RigidBody + +export (String, MULTILINE) var patch = "" +export (float, 0, 100) var audible_range_max = 10.0 + +var _use_earplug = false +var _my_patch = "res://main.pd" +var _my_id = 0 + +func set_size(size): + $CollisionShape.shape.radius = size + $MeshInstance.mesh.radius = size + $MeshInstance.mesh.height = size * 2 + +func set_freq(freq): + Global._gdpd.start_message(2) + Global._gdpd.add_symbol('freq') + Global._gdpd.add_float(freq) + Global._gdpd.finish_list("fromGodot" + String(_my_id)) + +func set_gain(gain): + Global._gdpd.start_message(2) + Global._gdpd.add_symbol('gain') + Global._gdpd.add_float(gain) + Global._gdpd.finish_list("fromGodot" + String(_my_id)) + +func set_color(color): + $MeshInstance.material_override = SpatialMaterial.new() + $MeshInstance.material_override.albedo_color = color + +func _ready(): + # save patch (for export) +# _save_patch() + + # load patch + _my_id = Global.load_patch(ProjectSettings.globalize_path(_my_patch)) + + # listen 'player_transform_updated' event + Events.connect("player_transform_updated", self, "_on_Events_player_transform_updated") + +func _on_Events_player_transform_updated(playerpos, playerheading): + var mypos = get_global_translation() + var mypos2d = Vector2(mypos.x, mypos.z) + var playerpos2d = Vector2(playerpos.x, playerpos.z) + # calculate distance + var distance = mypos.distance_to(playerpos) + # calculate angle + var angle = fmod(fmod(playerpos2d.angle_to_point(mypos2d) + playerheading - PI/2, PI*2) + PI*2, PI*2) +# if angle > PI: +# angle = angle - PI*2 + # radians to degrees +# if angle < 0: +# angle = angle + PI*2 + angle = rad2deg(angle) + # (check) +# print(str(_my_id) +" : ("+ str(distance) +","+ str(angle) +")") + # calculate gain +# var gain = max(1 - distance/audible_range_max, 0) + var gain = 1 - distance/audible_range_max + # send to the patch + Global._gdpd.start_message(3) + Global._gdpd.add_symbol("panvol") + Global._gdpd.add_float(gain) + Global._gdpd.add_float(angle) + Global._gdpd.finish_list("fromGodot" + String(_my_id)) + + +func _exit_tree(): + Global.close_patch(_my_id) + +func _save_patch(): + # save patch + # prepare directory + var patch_name = _my_patch.split("/")[-1] + var patch_dir = _my_patch.trim_suffix(patch_name) + var dir = Directory.new() + dir.make_dir_recursive(patch_dir) + # save to file + var file = File.new() + file.open(_my_patch, File.WRITE) + file.store_string(patch) + file.close() diff --git a/GdpdExample/main.pd b/GdpdExample/main.pd new file mode 100644 index 0000000..ccbb2eb --- /dev/null +++ b/GdpdExample/main.pd @@ -0,0 +1,53 @@ +#N canvas 574 271 456 518 12; +#X obj 361 21 loadbang; +#X msg 361 51 \; pd dsp 1; +#X floatatom 21 198 5 0 0 0 - - - 0; +#X obj 21 22 r fromGodot\$0; +#X obj 21 46 list trim; +#X obj 199 467 dac~ 1 2; +#X obj 199 407 *~; +#X obj 189 264 line~; +#X msg 189 240 \$1 100; +#X obj 189 127 unpack f f; +#X floatatom 189 177 5 0 0 0 - - - 0; +#X obj 21 256 noise~; +#X obj 21 286 bp~ 500 1000; +#X obj 21 70 route freq gain panvol; +#X obj 21 316 *~; +#X msg 296 338 \$1 100; +#X floatatom 296 159 5 0 0 0 - - - 0; +#X obj 199 437 earplug~ 0 0; +#X obj 296 362 line; +#X obj 132 310 switch~; +#X obj 132 286 tgl 19 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 132 262 change; +#X text 89 155 switch on/off before 0 to stop startup pops, f 12; +#X obj 189 216 max 0; +#X obj 132 238 > -0.3; +#X obj 296 248 expr 360-$f1; +#X connect 2 0 12 1; +#X connect 3 0 4 0; +#X connect 4 0 13 0; +#X connect 6 0 17 0; +#X connect 7 0 6 1; +#X connect 8 0 7 0; +#X connect 9 0 10 0; +#X connect 9 1 16 0; +#X connect 10 0 23 0; +#X connect 10 0 24 0; +#X connect 11 0 12 0; +#X connect 12 0 14 0; +#X connect 13 0 2 0; +#X connect 13 1 14 1; +#X connect 13 2 9 0; +#X connect 14 0 6 0; +#X connect 15 0 18 0; +#X connect 16 0 25 0; +#X connect 17 0 5 0; +#X connect 17 1 5 1; +#X connect 18 0 17 1; +#X connect 20 0 19 0; +#X connect 21 0 20 0; +#X connect 23 0 8 0; +#X connect 24 0 21 0; +#X connect 25 0 15 0; diff --git a/GdpdExample/osc.gd b/GdpdExample/osc.gd new file mode 100644 index 0000000..df084d1 --- /dev/null +++ b/GdpdExample/osc.gd @@ -0,0 +1,100 @@ +extends RigidBody + +export (String, MULTILINE) var patch = "" +export (float, 0, 100) var audible_range_max = 10.0 +export (float, 1, 12) var preset = 1 + +var _my_patch = "res://osc.pd" +var _my_id = 0 + +func set_size(size): + $CollisionShape.shape.radius = size + $MeshInstance.mesh.radius = size + $MeshInstance.mesh.height = size * 2 + +func set_freq(freq): + Global._gdpd.start_message(2) + Global._gdpd.add_symbol('freq') + Global._gdpd.add_float(freq) + Global._gdpd.finish_list("fromGodot" + String(_my_id)) + +func set_gain(gain): + Global._gdpd.start_message(2) + Global._gdpd.add_symbol('gain') + Global._gdpd.add_float(gain) + Global._gdpd.finish_list("fromGodot" + String(_my_id)) + +func set_param(param): + Global._gdpd.start_message(param.size()+1) + Global._gdpd.add_symbol("param") + for i in range(param.size()): + Global._gdpd.add_float(param[i]) + Global._gdpd.finish_list("fromGodot" + String(_my_id)) + +func set_preset(prs): + preset = prs + Global._gdpd.start_message(2) + Global._gdpd.add_symbol("preset") + Global._gdpd.add_float(prs) + Global._gdpd.finish_list("fromGodot" + String(_my_id)) + +func set_color(color): + $MeshInstance.material_override = SpatialMaterial.new() + $MeshInstance.material_override.albedo_color = color + +func _ready(): + # save patch (for export) +# _save_patch() + + # load patch + _my_id = Global.load_patch(ProjectSettings.globalize_path(_my_patch)) + + # listen 'player_transform_updated' event + Events.connect("player_transform_updated", self, "_on_Events_player_transform_updated") + + # send 'preset' + set_preset(preset) + +func _on_Events_player_transform_updated(playerpos, playerheading): + var mypos = get_global_translation() + var mypos2d = Vector2(mypos.x, mypos.z) + var playerpos2d = Vector2(playerpos.x, playerpos.z) + # calculate distance + var distance = mypos.distance_to(playerpos) + # calculate angle + var angle = fmod(fmod(playerpos2d.angle_to_point(mypos2d) + playerheading - PI/2, PI*2) + PI*2, PI*2) +# if angle > PI: +# angle = angle - PI*2 + # radians to degrees +# if angle < 0: +# angle = angle + PI*2 + angle = rad2deg(angle) + # (check) +# print(str(_my_id) +" : ("+ str(distance) +","+ str(angle) +")") + # calculate gain +# var gain = max(1 - distance/audible_range_max, 0) + var gain = 1 - distance/audible_range_max + # send to the patch + Global._gdpd.start_message(3) + Global._gdpd.add_symbol("panvol") + Global._gdpd.add_float(gain) + Global._gdpd.add_float(angle) + Global._gdpd.finish_list("fromGodot" + String(_my_id)) + + +func _exit_tree(): + Global.close_patch(_my_id) + pass + +func _save_patch(): + # save patch + # prepare directory + var patch_name = _my_patch.split("/")[-1] + var patch_dir = _my_patch.trim_suffix(patch_name) + var dir = Directory.new() + dir.make_dir_recursive(patch_dir) + # save to file + var file = File.new() + file.open(_my_patch, File.WRITE) + file.store_string(patch) + file.close() diff --git a/GdpdExample/osc.pd b/GdpdExample/osc.pd new file mode 100644 index 0000000..19b0592 --- /dev/null +++ b/GdpdExample/osc.pd @@ -0,0 +1,51 @@ +#N canvas 540 203 456 518 12; +#X obj 361 21 loadbang; +#X msg 361 51 \; pd dsp 1; +#X obj 50 277 osc~ 440; +#X floatatom 21 198 5 0 0 0 - - - 0; +#X obj 21 22 r fromGodot\$0; +#X obj 21 46 list trim; +#X obj 199 467 dac~ 1 2; +#X obj 199 407 *~; +#X obj 189 127 unpack f f; +#X obj 21 70 route freq gain panvol; +#X obj 50 301 *~; +#X msg 296 338 \$1 100; +#X floatatom 296 159 5 0 0 0 - - - 0; +#X obj 199 437 earplug~ 0 0; +#X obj 296 362 line; +#X obj 189 264 line~; +#X msg 189 240 \$1 100; +#X floatatom 189 177 5 0 0 0 - - - 0; +#X obj 132 310 switch~; +#X obj 132 286 tgl 19 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 132 262 change; +#X text 89 155 switch on/off before 0 to stop startup pops, f 12; +#X obj 189 216 max 0; +#X obj 132 238 > -0.3; +#X obj 296 248 expr 360-$f1; +#X connect 2 0 10 0; +#X connect 3 0 2 0; +#X connect 4 0 5 0; +#X connect 5 0 9 0; +#X connect 7 0 13 0; +#X connect 8 0 17 0; +#X connect 8 1 12 0; +#X connect 9 0 3 0; +#X connect 9 1 10 1; +#X connect 9 2 8 0; +#X connect 10 0 7 0; +#X connect 11 0 14 0; +#X connect 12 0 24 0; +#X connect 13 0 6 0; +#X connect 13 1 6 1; +#X connect 14 0 13 1; +#X connect 15 0 7 1; +#X connect 16 0 15 0; +#X connect 17 0 22 0; +#X connect 17 0 23 0; +#X connect 19 0 18 0; +#X connect 20 0 19 0; +#X connect 22 0 16 0; +#X connect 23 0 20 0; +#X connect 24 0 11 0; diff --git a/GdpdExample/osc.tscn b/GdpdExample/osc.tscn new file mode 100644 index 0000000..91e0835 --- /dev/null +++ b/GdpdExample/osc.tscn @@ -0,0 +1,68 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://osc.gd" type="Script" id=1] + +[sub_resource type="PhysicsMaterial" id=3] + +[sub_resource type="SphereShape" id=1] + +[sub_resource type="SphereMesh" id=2] +resource_local_to_scene = true + +[node name="osc" type="RigidBody" groups=["sounders"]] +collision_layer = 4 +collision_mask = 0 +physics_material_override = SubResource( 3 ) +gravity_scale = 0.0 +script = ExtResource( 1 ) +patch = "#N canvas 540 203 456 518 12; +#X obj 361 21 loadbang; +#X msg 361 51 \\; pd dsp 1; +#X obj 80 277 osc~ 440; +#X floatatom 21 198 5 0 0 0 - - - 0; +#X obj 21 22 r fromGodot\\$0; +#X obj 21 46 list trim; +#X obj 199 467 dac~ 1 2; +#X obj 199 407 *~; +#X obj 189 230 line~; +#X msg 189 206 \\$1 100; +#X obj 189 127 unpack f f; +#X floatatom 189 177 5 0 0 0 - - - 0; +#X obj 21 70 route freq gain panvol; +#X obj 80 301 *~; +#X msg 296 338 \\$1 100; +#X floatatom 296 159 5 0 0 0 - - - 0; +#X obj 199 437 earplug~ 0 0; +#X obj 296 362 line; +#X obj 122 158 != 0; +#X obj 122 206 switch~; +#X obj 122 182 tgl 19 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X connect 2 0 13 0; +#X connect 3 0 2 0; +#X connect 4 0 5 0; +#X connect 5 0 12 0; +#X connect 7 0 16 0; +#X connect 8 0 7 1; +#X connect 9 0 8 0; +#X connect 10 0 11 0; +#X connect 10 1 15 0; +#X connect 11 0 9 0; +#X connect 11 0 18 0; +#X connect 12 0 3 0; +#X connect 12 1 13 1; +#X connect 12 2 10 0; +#X connect 13 0 7 0; +#X connect 14 0 17 0; +#X connect 15 0 14 0; +#X connect 16 0 6 0; +#X connect 16 1 6 1; +#X connect 17 0 16 1; +#X connect 18 0 20 0; +#X connect 20 0 19 0; +" + +[node name="CollisionShape" type="CollisionShape" parent="."] +shape = SubResource( 1 ) + +[node name="MeshInstance" type="MeshInstance" parent="."] +mesh = SubResource( 2 ) diff --git a/GdpdExample/patch.pd b/GdpdExample/patch.pd deleted file mode 100644 index 8f7d2e2..0000000 --- a/GdpdExample/patch.pd +++ /dev/null @@ -1,28 +0,0 @@ -#N canvas 427 209 450 357 12; -#X obj 292 61 loadbang; -#X msg 292 91 \; pd dsp 1; -#X obj 92 86 t b; -#X obj 61 38 bng 19 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; -#X obj 300 299 dac~; -#X obj 300 239 osc~ 440; -#X obj 300 269 *~ 0.1; -#X obj 300 142 random 900; -#X obj 300 166 + 500; -#X floatatom 300 190 5 0 0 0 - - - 0; -#X obj 187 39 r fromGodot; -#X obj 117 308 s toGodot; -#X obj 117 278 list; -#X msg 117 248 random \$1; -#X connect 0 0 1 0; -#X connect 2 0 7 0; -#X connect 3 0 2 0; -#X connect 5 0 6 0; -#X connect 6 0 4 0; -#X connect 6 0 4 1; -#X connect 7 0 8 0; -#X connect 8 0 9 0; -#X connect 9 0 5 0; -#X connect 9 0 13 0; -#X connect 10 0 2 0; -#X connect 12 0 11 0; -#X connect 13 0 12 0; diff --git a/GdpdExample/patch1-node.pd b/GdpdExample/patch1-node.pd deleted file mode 100644 index 455bdb9..0000000 --- a/GdpdExample/patch1-node.pd +++ /dev/null @@ -1,15 +0,0 @@ -#N canvas 436 326 450 300 12; -#X obj 116 235 dac~; -#X obj 116 175 osc~ 440; -#X obj 116 205 *~ 0.1; -#X obj 116 78 random 900; -#X obj 116 102 + 500; -#X floatatom 116 126 5 0 0 0 - - - 0; -#X obj 99 29 inlet; -#X connect 1 0 2 0; -#X connect 2 0 0 0; -#X connect 2 0 0 1; -#X connect 3 0 4 0; -#X connect 4 0 5 0; -#X connect 5 0 1 0; -#X connect 6 0 3 0; diff --git a/GdpdExample/patch1.pd b/GdpdExample/patch1.pd deleted file mode 100644 index af0cc5d..0000000 --- a/GdpdExample/patch1.pd +++ /dev/null @@ -1,17 +0,0 @@ -#N canvas 203 306 402 347 12; -#X obj 292 61 loadbang; -#X obj 187 39 r blup; -#X msg 292 91 \; pd dsp 1; -#X obj 145 207 clone patch1-node 2; -#X floatatom 41 256 5 0 0 0 - - - 0; -#X msg 41 279 vis \$1 1; -#X msg 180 128 all bang; -#X obj 92 86 t b; -#X obj 61 38 bng 19 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; -#X connect 0 0 2 0; -#X connect 1 0 7 0; -#X connect 4 0 5 0; -#X connect 5 0 3 0; -#X connect 6 0 3 0; -#X connect 7 0 6 0; -#X connect 8 0 7 0; diff --git a/GdpdExample/patch2.pd b/GdpdExample/patch2.pd deleted file mode 100644 index 099314f..0000000 --- a/GdpdExample/patch2.pd +++ /dev/null @@ -1,24 +0,0 @@ -#N canvas 2 328 450 300 12; -#X obj 344 82 s pd; -#X obj 344 31 loadbang; -#X msg 344 55 dsp 1; -#X obj 152 134 dac~; -#X obj 152 110 *~ 0.1; -#X obj 152 86 osc~ 600; -#X obj 240 111 loadbang; -#X obj 241 141 metro 1000; -#X msg 240 168 patch2 0; -#X obj 230 239 s toBfWeb; -#X obj 247 207 list append; -#X obj 24 166 r toBfWeb; -#X obj 24 190 print patch2; -#X connect 1 0 2 0; -#X connect 2 0 0 0; -#X connect 4 0 3 0; -#X connect 4 0 3 1; -#X connect 5 0 4 0; -#X connect 6 0 7 0; -#X connect 7 0 8 0; -#X connect 8 0 10 0; -#X connect 10 0 9 0; -#X connect 11 0 12 0; diff --git a/GdpdExample/project.godot b/GdpdExample/project.godot index 16c4d2c..a23d57c 100644 --- a/GdpdExample/project.godot +++ b/GdpdExample/project.godot @@ -8,26 +8,59 @@ config_version=4 -_global_script_classes=[ ] -_global_script_class_icons={ -} - [application] -config/name="GdpdExample" -run/main_scene="res://Main.tscn" -run/low_processor_mode=true +config/name="Sands and Waves (worldscene1)" +run/main_scene="res://Scene.tscn" config/icon="res://icon.png" -[display] +[autoload] -window/size/width=480 -window/size/height=640 -window/stretch/mode="2d" -window/stretch/aspect="keep" +Global="*res://autoload/Global.tscn" +Events="*res://autoload/Events.tscn" + +[gui] + +common/drop_mouse_on_gui_input_disabled=true + +[input] + +move_right={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} +move_left={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} +move_forward={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":87,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} +move_backward={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":83,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} +toggle_mouse={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777217,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} + +[layer_names] + +3d_physics/layer_1="world" +3d_physics/layer_2="player" +3d_physics/layer_3="sounder" + +[physics] + +common/enable_pause_aware_picking=true [rendering] -vram_compression/import_etc=true -vram_compression/import_etc2=false environment/default_environment="res://default_env.tres" diff --git a/SConstruct b/SConstruct index 89b5572..4eed5ee 100644 --- a/SConstruct +++ b/SConstruct @@ -14,6 +14,7 @@ opts.Add(BoolVariable('use_llvm', "Use the LLVM / Clang compiler", 'no')) opts.Add(BoolVariable('use_mingw', "Use the MingW for cross-compiling", 'no')) opts.Add(PathVariable('target_path', 'The path where the lib is installed.', 'GdpdExample/addons/gdpd/bin/')) opts.Add(PathVariable('target_name', 'The library name.', 'libgdpd', PathVariable.PathAccept)) +opts.Add(EnumVariable("macos_arch", "Target macOS architecture", "universal", ["universal", "x86_64", "arm64"])) # Local dependency paths, adapt them to your setup godot_headers_path = "src/godot-cpp/godot-headers/" @@ -53,8 +54,15 @@ if env['platform'] == "osx": env['target_path'] += 'osx/' cpp_library += '.osx' env.Append(CPPDEFINES=['__MACOSX_CORE__', 'HAVE_UNISTD_H', 'LIBPD_EXTRA']) - env.Append(LINKFLAGS=['-arch', 'x86_64', '-arch', 'arm64', '-framework', 'CoreAudio', '-framework', 'CoreFoundation']) - env.Append(CCFLAGS=['-arch', 'x86_64', '-arch', 'arm64']) + + if env["macos_arch"] == "universal": + env.Append(LINKFLAGS=["-arch", "x86_64", "-arch", "arm64"]) + env.Append(CCFLAGS=["-arch", "x86_64", "-arch", "arm64"]) + else: + env.Append(LINKFLAGS=["-arch", env["macos_arch"]]) + env.Append(CCFLAGS=["-arch", env["macos_arch"]]) + + env.Append(LINKFLAGS=['-framework', 'CoreAudio', '-framework', 'CoreFoundation']) env.Append(CXXFLAGS=['-std=c++17']) if env['target'] in ('debug', 'd'): env.Append(CCFLAGS=['-g', '-O2']) diff --git a/src/gdpd.cpp b/src/gdpd.cpp index 4de6db6..a373ae0 100644 --- a/src/gdpd.cpp +++ b/src/gdpd.cpp @@ -21,6 +21,7 @@ void Gdpd::_register_methods() { register_method("computeAudio", &Gdpd::computeAudio); register_method("set_volume", &Gdpd::set_volume); register_method("set_gui_path", &Gdpd::set_gui_path); + register_method("set_verbose", &Gdpd::set_verbose); } int Gdpd::audioCallback(void *outputBuffer, void *inputBuffer, @@ -32,7 +33,7 @@ int Gdpd::audioCallback(void *outputBuffer, void *inputBuffer, return 0; } -Gdpd::Gdpd() : m_vol(0), m_gui_path("") { +Gdpd::Gdpd() : m_vol(0), m_gui_path(""), m_verbose(false) { //create message array m_messages = new Array(); m_init=false; @@ -281,7 +282,9 @@ int Gdpd::finish_list(String destStr) { } void Gdpd::print(const std::string& message) { - Godot::print((std::string("GDPD : ")+message).c_str()); + if (m_verbose) { + Godot::print((std::string("GDPD : ")+message).c_str()); + } } void Gdpd::receiveList(const std::string& dest, const pd::List& list) { @@ -314,3 +317,7 @@ void Gdpd::set_gui_path(godot::String pathStr) { void Gdpd::computeAudio(bool state) { //[; pd dsp 0/1 ( m_pd.computeAudio(state); } + +void Gdpd::set_verbose(bool verbose) { + m_verbose = verbose; +} diff --git a/src/gdpd.hpp b/src/gdpd.hpp index 17c9cd9..6ac4521 100644 --- a/src/gdpd.hpp +++ b/src/gdpd.hpp @@ -36,6 +36,7 @@ private: int m_outputDevice; std::map m_patchsMap; std::string m_gui_path; + bool m_verbose; bool m_init; @@ -77,7 +78,7 @@ public: inline const float& get_volume(){ return m_vol; } - + void set_verbose(bool verbose); //rtaudio static int audioCallback(void *outputBuffer, void *inputBuffer, diff --git a/src/rtaudio/RtAudio.os b/src/rtaudio/RtAudio.os index 98b15ed..48df239 100644 Binary files a/src/rtaudio/RtAudio.os and b/src/rtaudio/RtAudio.os differ diff --git a/update.sh b/update.sh index b70a526..1747658 100755 --- a/update.sh +++ b/update.sh @@ -1,6 +1,6 @@ #!/bin/bash git submodule update --init --recursive cd src/godot-cpp -scons platform=$1 target=$2 generate_bindings=yes +scons platform=$1 target=$2 macos_arch=$3 generate_bindings=yes cd ../.. -scons platform=$1 target=$2 +scons platform=$1 target=$2 macos_arch=$3