From f5b406c72fbd812fbc0b111872ab0bfeda6fb463 Mon Sep 17 00:00:00 2001 From: SchimmelSpreu83 Date: Thu, 16 Oct 2025 18:29:38 +0200 Subject: [PATCH] (Tried to) Implement a way to sync audio with animation --- .../everlasting_fun/_ef_chase_test.tscn | 4 + .../_experimental/CircusTent_texture_02.png | Bin 2774 -> 0 bytes .../CircusTent_texture_02.png.import | 44 ------- .../_experimental/CircusTent_texture_02_2.png | Bin 2774 -> 0 bytes .../CircusTent_texture_02_2.png.import | 44 ------- .../_experimental/CircusTent_texture_13.png | Bin 9867 -> 0 bytes .../CircusTent_texture_13.png.import | 44 ------- .../_experimental/_test_level.glb.import | 2 +- source/tools/anim_player_editor_calls.gd | 1 + source/tools/timed_music_animationplayer.gd | 110 ++++++++++++++++++ .../tools/timed_music_animationplayer.gd.uid | 1 + 11 files changed, 117 insertions(+), 133 deletions(-) delete mode 100644 source/_development/ayuroo/levels/_experimental/CircusTent_texture_02.png delete mode 100644 source/_development/ayuroo/levels/_experimental/CircusTent_texture_02.png.import delete mode 100644 source/_development/ayuroo/levels/_experimental/CircusTent_texture_02_2.png delete mode 100644 source/_development/ayuroo/levels/_experimental/CircusTent_texture_02_2.png.import delete mode 100644 source/_development/ayuroo/levels/_experimental/CircusTent_texture_13.png delete mode 100644 source/_development/ayuroo/levels/_experimental/CircusTent_texture_13.png.import create mode 100644 source/tools/timed_music_animationplayer.gd create mode 100644 source/tools/timed_music_animationplayer.gd.uid diff --git a/source/_development/ayuroo/levels/_chase_test/everlasting_fun/_ef_chase_test.tscn b/source/_development/ayuroo/levels/_chase_test/everlasting_fun/_ef_chase_test.tscn index 17b7f1a..0ec04da 100644 --- a/source/_development/ayuroo/levels/_chase_test/everlasting_fun/_ef_chase_test.tscn +++ b/source/_development/ayuroo/levels/_chase_test/everlasting_fun/_ef_chase_test.tscn @@ -50,11 +50,15 @@ stream = ExtResource("3_c4bhh") volume_db = -6.0 [node name="MusicAnimation" type="AnimationPlayer" parent="."] +audio_max_polyphony = 1 callback_mode_process = 0 +callback_mode_method = 1 libraries = { &"": ExtResource("2_r4hpf") } script = ExtResource("5_c4bhh") +audio_player = NodePath("../Music") +metadata/_custom_type_script = "uid://jahmwrxb2siw" [node name="ProgressTrack" type="Path3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) diff --git a/source/_development/ayuroo/levels/_experimental/CircusTent_texture_02.png b/source/_development/ayuroo/levels/_experimental/CircusTent_texture_02.png deleted file mode 100644 index dec5b59cc01a269635586fa27586d6b40e511fd0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2774 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UnsyQ z#P$C|!~bjC|1UQFKV9lS5cDwU@z^CYFmUC2x;TbZ+A`@48 Q-2s{7>FVdQ&MBb@0EF*zl>h($ diff --git a/source/_development/ayuroo/levels/_experimental/CircusTent_texture_02.png.import b/source/_development/ayuroo/levels/_experimental/CircusTent_texture_02.png.import deleted file mode 100644 index a3c4888..0000000 --- a/source/_development/ayuroo/levels/_experimental/CircusTent_texture_02.png.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://t47dsnj63y0q" -path.s3tc="res://.godot/imported/CircusTent_texture_02.png-4e53f948574944f15359cfab26877cc1.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} -generator_parameters={ -"md5": "a4091b6db3fc67af97a848a98d5046da" -} - -[deps] - -source_file="res://_development/ayuroo/levels/_experimental/CircusTent_texture_02.png" -dest_files=["res://.godot/imported/CircusTent_texture_02.png-4e53f948574944f15359cfab26877cc1.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=true -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/source/_development/ayuroo/levels/_experimental/CircusTent_texture_02_2.png b/source/_development/ayuroo/levels/_experimental/CircusTent_texture_02_2.png deleted file mode 100644 index bf1cb173ba132270f0d3e2a0d98a487927b652f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2774 zcmeAS@N?(olHy`uVBq!ia0y~yU;#2&7+9ErRIjnw1`sdZ(btiIVPik{pF~z5UnsyQ z#Pz>n+<*7{|HkqErF{Ma0fWVkpkgKl2CjTh7srr_TW_x&{~b2ezck)J2^D;GT2PAsyFaGBrzopr0Ij8R*Z=?k diff --git a/source/_development/ayuroo/levels/_experimental/CircusTent_texture_02_2.png.import b/source/_development/ayuroo/levels/_experimental/CircusTent_texture_02_2.png.import deleted file mode 100644 index 02e29be..0000000 --- a/source/_development/ayuroo/levels/_experimental/CircusTent_texture_02_2.png.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://pcmndib445ch" -path.s3tc="res://.godot/imported/CircusTent_texture_02_2.png-72d00f784254062ea8406c13e57b7f70.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} -generator_parameters={ -"md5": "671c567d75d6cffe7d16440771c026c5" -} - -[deps] - -source_file="res://_development/ayuroo/levels/_experimental/CircusTent_texture_02_2.png" -dest_files=["res://.godot/imported/CircusTent_texture_02_2.png-72d00f784254062ea8406c13e57b7f70.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=true -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/source/_development/ayuroo/levels/_experimental/CircusTent_texture_13.png b/source/_development/ayuroo/levels/_experimental/CircusTent_texture_13.png deleted file mode 100644 index 13c43884ccec7829d4b6d695e89ffebc2e440e61..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9867 zcmeHNcT|(vwm+fhC<5bH7#R?*Zy??u(^TnUC zwUFJYxDfy#YkA`6833e2ODXV`r08*i)L$xo^EIytgJAZOj}#KyLXdM zpSJ(`=i+D2o(~KRxVX4hRJ@#>o$cxAF)%P3A0HTMSEG&}AWHy`adef{%%@MR zy1M%J?|U9UesbuL-u(PL8jZ2Bu_F+wEG$k`RaNKY2c`?CefgSJzy;=y~FV)xyHU+}zycy(w1JvcZ>p-?`5{>PyTrLlb{V6y&#M;^>CgxgTAVODH|HFq5 z%gf7YY4=DZQek1CtLu4ZXP3CR_`JM_nVDH<&e)HPj2Idk_4oI8c6Nn^hCO(YZ(8>Xl-rt_y2KaWwpJ%y}P^H$?4pqNBJcsrPr^=hJ=KA zdHHm8b>VP7-M*dZ;BXd+yi#6XVQdWZ@VGcVJv}k;DIx+{SopNOyxiRU7#@$0jz%L8 z!JeL8=g+%)d;9eD^_@HCT3n3J&CNS}7)qsf`1=Qxm6eZ-jIvm)^z{2Mn3=x5K}$<3 zgTZifgI~E4`Sj_tl$2CDeOOP=U~Fs*3N>q7)hHYF*d0KkRGrsfNDE8pTi%F3^ADi4u^iL(IZrt^K-kD;DZKt*# zz2msA?CSW&8>yitE4Azl9jH!C^!8Kty;m||!zX*)#<*E=y}jNO_VFnx_HoAO{g#ta zF76Xa#221Ip&AD{B>(^?00#m1Bo8G2%1Z!TzH6{pd&W%O67@2yC;nxnzaX|vQ>+=C z47pD*$kA-2+7MVDTIx#)zL@brR9ntkM($`O*KAF8!JqCQX(uxx9V!a|2M-13gHL{A z3nlAlvA?FCSD-Ft?x2QIg|P7^oo2#60dvg?Fhv;*Cz$LC1%*xAY4thOaf}wsB2{lZF+1h)N&40G1fd!UBBH3+4Y~$Ll#$LQ!|%H4qPv6Ev`C#y1f`#6 zu><#bvxveJDlt5VqM-GmnGOTZYF@r%%wZ+v`!MAocLNicJ5p0bgNu-A=z(uU4iuK* z1=MB?k>5L&-i@&B4xAH2o7Y+rcJ1gv99f;dpa09ADxizYG+t>vq`XrwPuI^re8>ha zPeh79Pneg>gkgAAHJ zvj?t)U1KL$H+J5r7m&1CA=$-X4kYZSp) zM2K6KH0?V)5bhfX-|l0#K}ychEt_A~6UcaX*m9cn0V-xzp#qBc&-4+iRH6D04UkyE z%&dGS>kWJF0e#4?A48$#m_|Gbz)x z#aak36^4&mT%ESBrnPVItxjuKin?roj1cJJn5poW>i;cIZdaWiW`f;TIN@7xU1x9s ztHHY*+|oJ6^At-XQY~cxI;}6CFtKiIVn&vdMIi~sT*rmGKD~?)6I6T$x;m{JS!7=8 zBa~0`vEB=G-t6?ethK^ac74s`ΖXpz11goct0UA*^Gt@qN>o!qJ_IPdpPp9zf@ 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 pUkT&?-W>F^kf4x|&n1Pz^* diff --git a/source/_development/ayuroo/levels/_experimental/CircusTent_texture_13.png.import b/source/_development/ayuroo/levels/_experimental/CircusTent_texture_13.png.import deleted file mode 100644 index 42382be..0000000 --- a/source/_development/ayuroo/levels/_experimental/CircusTent_texture_13.png.import +++ /dev/null @@ -1,44 +0,0 @@ -[remap] - -importer="texture" -type="CompressedTexture2D" -uid="uid://ceoaurr14k8s0" -path.s3tc="res://.godot/imported/CircusTent_texture_13.png-733cbf96e6cf53acbb1f3cc2d83015cc.s3tc.ctex" -metadata={ -"imported_formats": ["s3tc_bptc"], -"vram_texture": true -} -generator_parameters={ -"md5": "5220913b82328d262f5516be440341d3" -} - -[deps] - -source_file="res://_development/ayuroo/levels/_experimental/CircusTent_texture_13.png" -dest_files=["res://.godot/imported/CircusTent_texture_13.png-733cbf96e6cf53acbb1f3cc2d83015cc.s3tc.ctex"] - -[params] - -compress/mode=2 -compress/high_quality=false -compress/lossy_quality=0.7 -compress/uastc_level=0 -compress/rdo_quality_loss=0.0 -compress/hdr_compression=1 -compress/normal_map=0 -compress/channel_pack=0 -mipmaps/generate=true -mipmaps/limit=-1 -roughness/mode=0 -roughness/src_normal="" -process/channel_remap/red=0 -process/channel_remap/green=1 -process/channel_remap/blue=2 -process/channel_remap/alpha=3 -process/fix_alpha_border=true -process/premult_alpha=false -process/normal_map_invert_y=false -process/hdr_as_srgb=false -process/hdr_clamp_exposure=false -process/size_limit=0 -detect_3d/compress_to=0 diff --git a/source/_development/ayuroo/levels/_experimental/_test_level.glb.import b/source/_development/ayuroo/levels/_experimental/_test_level.glb.import index 446c1f4..207105e 100644 --- a/source/_development/ayuroo/levels/_experimental/_test_level.glb.import +++ b/source/_development/ayuroo/levels/_experimental/_test_level.glb.import @@ -57,4 +57,4 @@ _subresources={ } } gltf/naming_version=2 -gltf/embedded_image_handling=1 +gltf/embedded_image_handling=0 diff --git a/source/tools/anim_player_editor_calls.gd b/source/tools/anim_player_editor_calls.gd index 235a213..36f4b24 100644 --- a/source/tools/anim_player_editor_calls.gd +++ b/source/tools/anim_player_editor_calls.gd @@ -1,4 +1,5 @@ @tool +class_name AnimPlayerEditorCalls extends AnimationPlayer var EDITOR_PATH: String: diff --git a/source/tools/timed_music_animationplayer.gd b/source/tools/timed_music_animationplayer.gd new file mode 100644 index 0000000..8a3c5b3 --- /dev/null +++ b/source/tools/timed_music_animationplayer.gd @@ -0,0 +1,110 @@ +@tool +class_name TimedMusicAnimationPlayer +extends AnimPlayerEditorCalls + +@export_node_path("AudioStreamPlayer", "AudioStreamPlayer2D", "AudioStreamPlayer3D") +var audio_player: NodePath = ^"": set = set_audio_player +## The index in the animation where the music is played from. +@export var music_anim_track_index: int = 0 +# The offset from 0.0 seconds when the music starts in the animation. +#@export var music_anim_offset: float = 0.0 +@export var max_error: float = 0.02175 +@export var min_pitch_scale_range: float = 0.0015 +@export var max_pitch_scale_range: float = 0.375 +@export var max_pitch_scale_difference: float = 1.01 +@export var custom_pitch_scale: float = 1.0 + +var _audio_player: Node +var _timer := Timer.new() +var _offset: float = 0.0 + + +func _ready() -> void: + super() + + if not Engine.is_editor_hint(): + add_child(_timer) + _timer.one_shot = false + + set_audio_player(audio_player) + animation_started.connect(_anim_started) + + +func _process(delta: float) -> void: + if Engine.is_editor_hint(): + super(delta) + return + + if not active or not is_playing() or not is_instance_valid(_audio_player): + return + + var latency: float = AudioServer.get_output_latency() + var audio_position: float = _audio_player.get_playback_position() + var anim_position: float = current_animation_position + AudioServer.get_time_since_last_mix() + var offset: float = anim_position - (audio_position + _offset) + var abs_offset: float = absf(offset) + + SPrint.print_msgf("Audio-Position: %s\nAnim-Position: %s" % [audio_position, anim_position]) + SPrint.print_msgf("Audio-Anim Diff: %s" % [audio_position - anim_position]) + SPrint.print_msgf("Audio-Pitch: %s\nLatency: %s" % [_audio_player.pitch_scale, latency]) + + if abs_offset < max_pitch_scale_range and abs_offset > latency:#min_pitch_scale_range: + var max_pitch_scale: float = max_pitch_scale_difference + var min_pitch_scale: float = custom_pitch_scale + (custom_pitch_scale - max_pitch_scale) + + var pitch: float = custom_pitch_scale + offset + latency + pitch = clampf(pitch, min_pitch_scale, max_pitch_scale) + pitch = lerp(_audio_player.pitch_scale, pitch, 1.0 - pow(0.5, delta)) + + _audio_player.pitch_scale = clampf(pitch, min_pitch_scale, max_pitch_scale) + elif abs_offset > max_error: + #_audio_player.seek(offset) + _audio_player.play((anim_position + _offset) - latency) + SPrint.print_msg("Snapped Audio to: %s" % [_audio_player.get_playback_position()]) + else: + _audio_player.pitch_scale = custom_pitch_scale + + +#func play_timed( + #anim_name: StringName, + #from_marker: StringName = &"", + #end_marker: StringName = &"", + #custom_blend: float = -1.0, + #custom_speed: float = 1.0, + #from_end: bool = false +#) -> void: + #_anim_started(anim_name) + #play_section_with_markers(anim_name, from_marker, end_marker, custom_blend, custom_speed, from_end) + + +func set_audio_player(path: NodePath) -> void: + audio_player = path + + var node: Node = get_node_or_null(path) + _audio_player = node if Utils.is_node_audioplayer(node) else null + + +func _anim_started(anim_name: StringName) -> void: + if Engine.is_editor_hint(): + return + + var animation: Animation = get_animation(anim_name) + animation.track_set_enabled(music_anim_track_index, false) + _audio_player.stream = null + + _offset = animation.track_get_key_time(music_anim_track_index, 0) + var duration: float = _offset - current_animation_position + + if duration > 0.0: + _timer.start(duration) + + var _signals: Array[Signal] = await SignalGroup.await_signals( + [_timer.timeout, animation_finished, animation_changed], 1 + ) + + if not _signals.front() == _timer.timeout: + return + + var latency: float = AudioServer.get_output_latency() - AudioServer.get_time_to_next_mix() + _audio_player.stream = animation.audio_track_get_key_stream(music_anim_track_index, 0) + _audio_player.play(current_animation_position - _offset - latency) diff --git a/source/tools/timed_music_animationplayer.gd.uid b/source/tools/timed_music_animationplayer.gd.uid new file mode 100644 index 0000000..aaa5446 --- /dev/null +++ b/source/tools/timed_music_animationplayer.gd.uid @@ -0,0 +1 @@ +uid://jahmwrxb2siw