summaryrefslogtreecommitdiff
path: root/scene/animation/animation_player.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/animation/animation_player.cpp')
-rw-r--r--scene/animation/animation_player.cpp234
1 files changed, 149 insertions, 85 deletions
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 63e0fb6935..1b7615befa 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -431,6 +431,17 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_ov
}
}
+ if (a->track_get_type(i) == Animation::TYPE_AUDIO) {
+ if (!node_cache->audio_anim.has(a->track_get_path(i).get_concatenated_names())) {
+ TrackNodeCache::AudioAnim aa;
+ aa.object = (Object *)child;
+ aa.audio_stream.instantiate();
+ aa.audio_stream->set_polyphony(audio_max_polyphony);
+
+ node_cache->audio_anim[a->track_get_path(i).get_concatenated_names()] = aa;
+ }
+ }
+
node_cache->last_setup_pass = setup_pass;
}
}
@@ -820,52 +831,40 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
if (!nc->node || is_stopping) {
continue;
}
-
- if (p_seeked) {
#ifdef TOOLS_ENABLED
- if (!can_call) {
- continue; // To avoid spamming the preview in editor.
- }
+ if (p_seeked && !can_call) {
+ continue; // To avoid spamming the preview in editor.
+ }
#endif // TOOLS_ENABLED
- int idx = a->track_find_key(i, p_time);
- if (idx < 0) {
- continue;
- }
-
- Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);
- if (!stream.is_valid()) {
- nc->node->call(SNAME("stop"));
- nc->audio_playing = false;
- playing_caches.erase(nc);
- } else {
- float start_ofs = a->audio_track_get_key_start_offset(i, idx);
- start_ofs += p_time - a->track_get_key_time(i, idx);
- float end_ofs = a->audio_track_get_key_end_offset(i, idx);
- float len = stream->get_length();
-
- if (start_ofs > len - end_ofs) {
- nc->node->call(SNAME("stop"));
- nc->audio_playing = false;
- playing_caches.erase(nc);
- continue;
- }
-
- nc->node->call(SNAME("set_stream"), stream);
- nc->node->call(SNAME("play"), start_ofs);
+ HashMap<StringName, TrackNodeCache::AudioAnim>::Iterator E = nc->audio_anim.find(a->track_get_path(i).get_concatenated_names());
+ ERR_CONTINUE(!E); //should it continue, or create a new one?
- nc->audio_playing = true;
- playing_caches.insert(nc);
- if (len && end_ofs > 0) { //force an end at a time
- nc->audio_len = len - start_ofs - end_ofs;
- } else {
- nc->audio_len = 0;
- }
+ TrackNodeCache::AudioAnim *aa = &E->value;
+ Node *asp = Object::cast_to<Node>(aa->object);
+ if (!asp) {
+ continue;
+ }
+ aa->length = a->get_length();
+ aa->time = p_time;
+ aa->loop = a->get_loop_mode() != Animation::LOOP_NONE;
+ aa->backward = backward;
+ if (aa->accum_pass != accum_pass) {
+ ERR_CONTINUE(cache_update_audio_size >= NODE_CACHE_UPDATE_MAX);
+ cache_update_audio[cache_update_audio_size++] = aa;
+ aa->accum_pass = accum_pass;
+ }
- nc->audio_start = p_time;
+ HashMap<int, TrackNodeCache::PlayingAudioStreamInfo> &map = aa->playing_streams;
+ // Find stream.
+ int idx = -1;
+ if (p_seeked) {
+ idx = a->track_find_key(i, p_time);
+ // Discard previous stream when seeking.
+ if (map.has(idx)) {
+ aa->audio_stream_playback->stop_stream(map[idx].index);
+ map.erase(idx);
}
-
} else {
- //find stuff to play
List<int> to_play;
if (p_started) {
int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT);
@@ -875,55 +874,47 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
}
a->track_get_key_indices_in_range(i, p_time, p_delta, &to_play, p_looped_flag);
if (to_play.size()) {
- int idx = to_play.back()->get();
-
- Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);
- if (!stream.is_valid()) {
- nc->node->call(SNAME("stop"));
- nc->audio_playing = false;
- playing_caches.erase(nc);
- } else {
- float start_ofs = a->audio_track_get_key_start_offset(i, idx);
- float end_ofs = a->audio_track_get_key_end_offset(i, idx);
- float len = stream->get_length();
-
- nc->node->call(SNAME("set_stream"), stream);
- nc->node->call(SNAME("play"), start_ofs);
-
- nc->audio_playing = true;
- playing_caches.insert(nc);
- if (len && end_ofs > 0) { //force an end at a time
- nc->audio_len = len - start_ofs - end_ofs;
- } else {
- nc->audio_len = 0;
- }
-
- nc->audio_start = p_time;
- }
- } else if (nc->audio_playing) {
- bool loop = a->get_loop_mode() != Animation::LOOP_NONE;
-
- bool stop = false;
-
- if (!loop) {
- if ((p_time < nc->audio_start && !backward) || (p_time > nc->audio_start && backward)) {
- stop = true;
- }
- } else if (nc->audio_len > 0) {
- float len = nc->audio_start > p_time ? (a->get_length() - nc->audio_start) + p_time : p_time - nc->audio_start;
+ idx = to_play.back()->get();
+ }
+ }
+ if (idx < 0) {
+ continue;
+ }
- if (len > nc->audio_len) {
- stop = true;
- }
+ // Play stream.
+ Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx);
+ if (stream.is_valid()) {
+ double start_ofs = a->audio_track_get_key_start_offset(i, idx);
+ double end_ofs = a->audio_track_get_key_end_offset(i, idx);
+ double len = stream->get_length();
+
+ if (aa->object->call(SNAME("get_stream")) != aa->audio_stream) {
+ aa->object->call(SNAME("set_stream"), aa->audio_stream);
+ aa->audio_stream_playback.unref();
+ if (!playing_audio_stream_players.has(asp)) {
+ playing_audio_stream_players.push_back(asp);
}
+ }
+ if (!aa->object->call(SNAME("is_playing"))) {
+ aa->object->call(SNAME("play"));
+ }
+ if (!aa->object->call(SNAME("has_stream_playback"))) {
+ aa->audio_stream_playback.unref();
+ continue;
+ }
+ if (aa->audio_stream_playback.is_null()) {
+ aa->audio_stream_playback = aa->object->call(SNAME("get_stream_playback"));
+ }
- if (stop) {
- //time to stop
- nc->node->call(SNAME("stop"));
- nc->audio_playing = false;
- playing_caches.erase(nc);
- }
+ TrackNodeCache::PlayingAudioStreamInfo pasi;
+ pasi.index = aa->audio_stream_playback->play_stream(stream, start_ofs);
+ pasi.start = p_time;
+ if (len && end_ofs > 0) { // Force an end at a time.
+ pasi.len = len - start_ofs - end_ofs;
+ } else {
+ pasi.len = 0;
}
+ map[idx] = pasi;
}
} break;
@@ -1223,6 +1214,53 @@ void AnimationPlayer::_animation_update_transforms() {
ERR_CONTINUE(ba->accum_pass != accum_pass);
ba->object->set_indexed(ba->bezier_property, ba->bezier_accum);
}
+
+ for (int i = 0; i < cache_update_audio_size; i++) {
+ TrackNodeCache::AudioAnim *aa = cache_update_audio[i];
+
+ ERR_CONTINUE(aa->accum_pass != accum_pass);
+
+ // Audio ending process.
+ LocalVector<int> erase_list;
+ for (const KeyValue<int, TrackNodeCache::PlayingAudioStreamInfo> &K : aa->playing_streams) {
+ TrackNodeCache::PlayingAudioStreamInfo pasi = K.value;
+
+ bool stop = false;
+ if (!aa->audio_stream_playback->is_stream_playing(pasi.index)) {
+ stop = true;
+ }
+ if (!aa->loop) {
+ if (!aa->backward) {
+ if (aa->time < pasi.start) {
+ stop = true;
+ }
+ } else if (aa->backward) {
+ if (aa->time > pasi.start) {
+ stop = true;
+ }
+ }
+ }
+ if (pasi.len > 0) {
+ double len = 0.0;
+ if (!aa->backward) {
+ len = pasi.start > aa->time ? (aa->length - pasi.start) + aa->time : aa->time - pasi.start;
+ } else {
+ len = pasi.start < aa->time ? (aa->length - aa->time) + pasi.start : pasi.start - aa->time;
+ }
+ if (len > pasi.len) {
+ stop = true;
+ }
+ }
+ if (stop) {
+ // Time to stop.
+ aa->audio_stream_playback->stop_stream(pasi.index);
+ erase_list.push_back(K.key);
+ }
+ }
+ for (uint32_t erase_idx = 0; erase_idx < erase_list.size(); erase_idx++) {
+ aa->playing_streams.erase(erase_list[erase_idx]);
+ }
+ }
}
void AnimationPlayer::_animation_process(double p_delta) {
@@ -1238,6 +1276,7 @@ void AnimationPlayer::_animation_process(double p_delta) {
cache_update_size = 0;
cache_update_prop_size = 0;
cache_update_bezier_size = 0;
+ cache_update_audio_size = 0;
AnimationData *prev_from = playback.current.from;
_animation_process2(p_delta, started);
@@ -1675,6 +1714,7 @@ void AnimationPlayer::play(const StringName &p_name, double p_custom_blend, floa
}
if (get_current_animation() != p_name) {
+ _clear_audio_streams();
_stop_playing_caches(false);
}
@@ -1856,6 +1896,7 @@ void AnimationPlayer::_node_removed(Node *p_node) {
}
void AnimationPlayer::clear_caches() {
+ _clear_audio_streams();
_stop_playing_caches(true);
node_cache_map.clear();
@@ -1867,10 +1908,19 @@ void AnimationPlayer::clear_caches() {
cache_update_size = 0;
cache_update_prop_size = 0;
cache_update_bezier_size = 0;
+ cache_update_audio_size = 0;
emit_signal(SNAME("caches_cleared"));
}
+void AnimationPlayer::_clear_audio_streams() {
+ for (int i = 0; i < playing_audio_stream_players.size(); i++) {
+ playing_audio_stream_players[i]->call(SNAME("stop"));
+ playing_audio_stream_players[i]->call(SNAME("set_stream"), Ref<AudioStream>());
+ }
+ playing_audio_stream_players.clear();
+}
+
void AnimationPlayer::set_active(bool p_active) {
if (active == p_active) {
return;
@@ -1950,6 +2000,15 @@ AnimationPlayer::AnimationMethodCallMode AnimationPlayer::get_method_call_mode()
return method_call_mode;
}
+void AnimationPlayer::set_audio_max_polyphony(int p_audio_max_polyphony) {
+ ERR_FAIL_COND(p_audio_max_polyphony < 0 || p_audio_max_polyphony > 128);
+ audio_max_polyphony = p_audio_max_polyphony;
+}
+
+int AnimationPlayer::get_audio_max_polyphony() const {
+ return audio_max_polyphony;
+}
+
void AnimationPlayer::set_movie_quit_on_finish_enabled(bool p_enabled) {
movie_quit_on_finish = p_enabled;
}
@@ -1978,6 +2037,7 @@ void AnimationPlayer::_set_process(bool p_process, bool p_force) {
}
void AnimationPlayer::_stop_internal(bool p_reset, bool p_keep_state) {
+ _clear_audio_streams();
_stop_playing_caches(p_reset);
Playback &c = playback;
c.blend.clear();
@@ -2198,6 +2258,9 @@ void AnimationPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_method_call_mode", "mode"), &AnimationPlayer::set_method_call_mode);
ClassDB::bind_method(D_METHOD("get_method_call_mode"), &AnimationPlayer::get_method_call_mode);
+ ClassDB::bind_method(D_METHOD("set_audio_max_polyphony", "max_polyphony"), &AnimationPlayer::set_audio_max_polyphony);
+ ClassDB::bind_method(D_METHOD("get_audio_max_polyphony"), &AnimationPlayer::get_audio_max_polyphony);
+
ClassDB::bind_method(D_METHOD("set_movie_quit_on_finish_enabled", "enabled"), &AnimationPlayer::set_movie_quit_on_finish_enabled);
ClassDB::bind_method(D_METHOD("is_movie_quit_on_finish_enabled"), &AnimationPlayer::is_movie_quit_on_finish_enabled);
@@ -2223,6 +2286,7 @@ void AnimationPlayer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playback_active", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_active", "is_active");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "-64,64,0.01"), "set_speed_scale", "get_speed_scale");
ADD_PROPERTY(PropertyInfo(Variant::INT, "method_call_mode", PROPERTY_HINT_ENUM, "Deferred,Immediate"), "set_method_call_mode", "get_method_call_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "audio_max_polyphony", PROPERTY_HINT_RANGE, "1,127,1"), "set_audio_max_polyphony", "get_audio_max_polyphony");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "movie_quit_on_finish"), "set_movie_quit_on_finish_enabled", "is_movie_quit_on_finish_enabled");