1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

Implement blending audio feature to AnimationTree

This commit is contained in:
Silc Renew
2023-01-28 03:25:49 +09:00
parent a43db5afa4
commit 75330887d7
22 changed files with 566 additions and 215 deletions

View File

@@ -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;
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?
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;
}
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);
}
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);
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 {
//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();
idx = to_play.back()->get();
}
}
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);
float end_ofs = a->audio_track_get_key_end_offset(i, idx);
float len = stream->get_length();
// 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();
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;
if (len > nc->audio_len) {
stop = true;
}
}
if (stop) {
//time to stop
nc->node->call(SNAME("stop"));
nc->audio_playing = false;
playing_caches.erase(nc);
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"));
}
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");