MagicNStuff/source/tools/timed_music_animationplayer.gd

111 lines
3.7 KiB
GDScript

@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)