diff --git a/doc/base/classes.xml b/doc/base/classes.xml
index aad217b8eb1..0f3e1a3f0cb 100644
--- a/doc/base/classes.xml
+++ b/doc/base/classes.xml
@@ -33677,6 +33677,7 @@
Library that contains a collection of [Sample], each identified by a text ID. This is used as a data container for the majority of the SamplePlayer classes and derivatives.
+ Sample players will never yield an active (currently playing) voice for a new playback request when there are no inactive voices available if the priority of the sample requested to be played is lower than that of every currently played samples.
@@ -33737,6 +33738,15 @@
Return the volume (in dB) for the given sample.
+
+
+
+
+
+
+ Return the priority for the given sample.
+
+
@@ -33755,6 +33765,15 @@
Set the volume (in dB) for the given sample.
+
+
+
+
+
+
+ Set the priority for the given sample.
+
+
diff --git a/editor/plugins/sample_library_editor_plugin.cpp b/editor/plugins/sample_library_editor_plugin.cpp
index 08231d6eb93..f626b4d33ad 100644
--- a/editor/plugins/sample_library_editor_plugin.cpp
+++ b/editor/plugins/sample_library_editor_plugin.cpp
@@ -175,6 +175,11 @@ void SampleLibraryEditor::_item_edited() {
StringName n = s->get_text(0);
sample_library->sample_set_pitch_scale(n, s->get_range(4));
+
+ } else if (tree->get_selected_column() == 5) { // Priority
+
+ StringName n = s->get_text(0);
+ sample_library->sample_set_priority(n, s->get_range(5));
}
}
@@ -248,9 +253,16 @@ void SampleLibraryEditor::_update_library() {
ti->set_editable(4, true);
ti->set_range(4, sample_library->sample_get_pitch_scale(E->get()));
+ // Priority
+ ti->set_cell_mode(5, TreeItem::CELL_MODE_RANGE);
+ ti->set_range_config(5, 0, 100, 1);
+ ti->set_selectable(5, true);
+ ti->set_editable(5, true);
+ ti->set_range(5, sample_library->sample_get_priority(E->get()));
+
// Delete
- ti->set_cell_mode(5, TreeItem::CELL_MODE_STRING);
- ti->add_button(5, get_icon("Remove", "EditorIcons"));
+ ti->set_cell_mode(6, TreeItem::CELL_MODE_STRING);
+ ti->add_button(6, get_icon("Remove", "EditorIcons"));
}
//player->add_sample("default",sample);
@@ -411,7 +423,7 @@ SampleLibraryEditor::SampleLibraryEditor() {
file->set_mode(EditorFileDialog::MODE_OPEN_FILES);
tree = memnew(Tree);
- tree->set_columns(6);
+ tree->set_columns(7);
add_child(tree);
tree->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 5);
tree->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 5);
@@ -423,18 +435,21 @@ SampleLibraryEditor::SampleLibraryEditor() {
tree->set_column_title(2, TTR("Format"));
tree->set_column_title(3, "dB");
tree->set_column_title(4, TTR("Pitch"));
- tree->set_column_title(5, "");
+ tree->set_column_title(5, TTR("Priority"));
+ tree->set_column_title(6, "");
tree->set_column_min_width(1, 150);
tree->set_column_min_width(2, 100);
tree->set_column_min_width(3, 50);
tree->set_column_min_width(4, 50);
- tree->set_column_min_width(5, 32);
+ tree->set_column_min_width(5, 60);
+ tree->set_column_min_width(6, 32);
tree->set_column_expand(1, false);
tree->set_column_expand(2, false);
tree->set_column_expand(3, false);
tree->set_column_expand(4, false);
tree->set_column_expand(5, false);
+ tree->set_column_expand(6, false);
tree->set_drag_forwarding(this);
diff --git a/scene/2d/sample_player_2d.cpp b/scene/2d/sample_player_2d.cpp
index 07f0e3fb36b..5e958058aa8 100644
--- a/scene/2d/sample_player_2d.cpp
+++ b/scene/2d/sample_player_2d.cpp
@@ -130,8 +130,9 @@ SamplePlayer2D::VoiceID SamplePlayer2D::play(const String &p_sample, int p_voice
Ref sample = library->get_sample(p_sample);
float vol_change = library->sample_get_volume_db(p_sample);
float pitch_change = library->sample_get_pitch_scale(p_sample);
+ int priority = library->sample_get_priority(p_sample);
- VoiceID vid = SpatialSound2DServer::get_singleton()->source_play_sample(get_source_rid(), sample->get_rid(), sample->get_mix_rate() * pitch_change, p_voice);
+ VoiceID vid = SpatialSound2DServer::get_singleton()->source_play_sample(get_source_rid(), sample->get_rid(), sample->get_mix_rate() * pitch_change, p_voice, priority);
if (vol_change)
SpatialSound2DServer::get_singleton()->source_voice_set_volume_scale_db(get_source_rid(), vid, vol_change);
diff --git a/scene/3d/spatial_sample_player.cpp b/scene/3d/spatial_sample_player.cpp
index c2860b4f703..25873bcfb96 100644
--- a/scene/3d/spatial_sample_player.cpp
+++ b/scene/3d/spatial_sample_player.cpp
@@ -130,6 +130,7 @@ SpatialSamplePlayer::VoiceID SpatialSamplePlayer::play(const String &p_sample, i
Ref sample = library->get_sample(p_sample);
float vol_change = library->sample_get_volume_db(p_sample);
float pitch_change = library->sample_get_pitch_scale(p_sample);
+ int priority = library->sample_get_priority(p_sample);
VoiceID vid = SpatialSoundServer::get_singleton()->source_play_sample(get_source_rid(), sample->get_rid(), sample->get_mix_rate() * pitch_change, p_voice);
if (vol_change)
diff --git a/scene/audio/sample_player.cpp b/scene/audio/sample_player.cpp
index dfccc5c7ce4..416d560b754 100644
--- a/scene/audio/sample_player.cpp
+++ b/scene/audio/sample_player.cpp
@@ -187,6 +187,7 @@ void SamplePlayer::Voice::clear() {
reverb_room = REVERB_HALL;
reverb_send = 0;
active = false;
+ priority = 0;
}
SamplePlayer::Voice::~Voice() {
@@ -214,13 +215,28 @@ SamplePlayer::VoiceID SamplePlayer::play(const String &p_name, bool unique) {
Ref sample = library->get_sample(p_name);
float vol_change = library->sample_get_volume_db(p_name);
float pitch_change = library->sample_get_pitch_scale(p_name);
+ int priority = library->sample_get_priority(p_name);
last_check++;
- last_id = (last_id + 1) % voices.size();
+
+ const int num_voices = voices.size();
+ bool found = false;
+ for (int i = 0; i < num_voices; i++) {
+ const int candidate = (last_id + 1 + i) % num_voices;
+ if (voices[candidate].priority <= priority) {
+ found = true;
+ last_id = candidate;
+ break;
+ }
+ }
+
+ if (!found)
+ return INVALID_VOICE_ID;
Voice &v = voices[last_id];
v.clear();
+ v.priority = priority;
v.mix_rate = sample->get_mix_rate() * (_default.pitch_scale * pitch_change);
v.sample_mix_rate = sample->get_mix_rate();
v.check = last_check;
diff --git a/scene/audio/sample_player.h b/scene/audio/sample_player.h
index 0f026a08533..392679f05ff 100644
--- a/scene/audio/sample_player.h
+++ b/scene/audio/sample_player.h
@@ -74,6 +74,7 @@ private:
uint32_t check;
bool active;
+ int priority;
int sample_mix_rate;
int mix_rate;
float volume;
diff --git a/scene/resources/sample_library.cpp b/scene/resources/sample_library.cpp
index e6ccdceb36f..752b988d80f 100644
--- a/scene/resources/sample_library.cpp
+++ b/scene/resources/sample_library.cpp
@@ -49,6 +49,7 @@ bool SampleLibrary::_set(const StringName &p_name, const Variant &p_value) {
sd.sample = d["sample"];
sd.pitch_scale = d["pitch"];
sd.db = d["db"];
+ sd.priority = d.has("priority") ? d["priority"] : Variant(0); // For libraries before priority was introduced
}
sample_map[name] = sd;
@@ -70,6 +71,7 @@ bool SampleLibrary::_get(const StringName &p_name, Variant &r_ret) const {
d["sample"] = sample_map[name].sample;
d["pitch"] = sample_map[name].pitch_scale;
d["db"] = sample_map[name].db;
+ d["priority"] = sample_map[name].priority;
r_ret = d;
} else {
return false;
@@ -170,6 +172,19 @@ float SampleLibrary::sample_get_pitch_scale(const StringName &p_name) const {
return sample_map[p_name].pitch_scale;
}
+void SampleLibrary::sample_set_priority(const StringName &p_name, int p_priority) {
+
+ ERR_FAIL_COND(!sample_map.has(p_name));
+ sample_map[p_name].priority = p_priority;
+}
+
+int SampleLibrary::sample_get_priority(const StringName &p_name) const {
+
+ ERR_FAIL_COND_V(!sample_map.has(p_name), 0);
+
+ return sample_map[p_name].priority;
+}
+
Array SampleLibrary::_get_sample_list() const {
List snames;
@@ -199,6 +214,9 @@ void SampleLibrary::_bind_methods() {
ObjectTypeDB::bind_method(_MD("sample_set_pitch_scale", "name", "pitch"), &SampleLibrary::sample_set_pitch_scale);
ObjectTypeDB::bind_method(_MD("sample_get_pitch_scale", "name"), &SampleLibrary::sample_get_pitch_scale);
+
+ ObjectTypeDB::bind_method(_MD("sample_set_priority", "name", "priority"), &SampleLibrary::sample_set_priority);
+ ObjectTypeDB::bind_method(_MD("sample_get_priority", "name"), &SampleLibrary::sample_get_priority);
}
SampleLibrary::SampleLibrary() {
diff --git a/scene/resources/sample_library.h b/scene/resources/sample_library.h
index 1928e55bb2d..d8008106b81 100644
--- a/scene/resources/sample_library.h
+++ b/scene/resources/sample_library.h
@@ -42,10 +42,12 @@ class SampleLibrary : public Resource {
Ref sample;
float db;
float pitch_scale;
+ int priority;
SampleData() {
db = 0;
pitch_scale = 1;
+ priority = 0;
}
};
@@ -67,6 +69,8 @@ public:
float sample_get_volume_db(const StringName &p_name) const;
void sample_set_pitch_scale(const StringName &p_name, float p_pitch);
float sample_get_pitch_scale(const StringName &p_name) const;
+ void sample_set_priority(const StringName &p_name, int p_priority);
+ int sample_get_priority(const StringName &p_name) const;
Ref get_sample(const StringName &p_name) const;
void get_sample_list(List *p_samples) const;
void remove_sample(const StringName &p_name);
diff --git a/servers/spatial_sound/spatial_sound_server_sw.cpp b/servers/spatial_sound/spatial_sound_server_sw.cpp
index b6021d8964a..410159d23c9 100644
--- a/servers/spatial_sound/spatial_sound_server_sw.cpp
+++ b/servers/spatial_sound/spatial_sound_server_sw.cpp
@@ -97,6 +97,7 @@ SpatialSoundServerSW::Source::Voice::Voice() {
active = false;
restart = false;
+ priority = 0;
pitch_scale = 1.0;
volume_scale = 0.0;
voice_rid = AudioServer::get_singleton()->voice_create();
@@ -390,7 +391,7 @@ void SpatialSoundServerSW::source_set_audio_stream(RID p_source, AudioServer::Au
} //null to unset
-SpatialSoundServer::SourceVoiceID SpatialSoundServerSW::source_play_sample(RID p_source, RID p_sample, int p_mix_rate, int p_voice) {
+SpatialSoundServer::SourceVoiceID SpatialSoundServerSW::source_play_sample(RID p_source, RID p_sample, int p_mix_rate, int p_voice, int p_priority) {
Source *source = source_owner.get(p_source);
ERR_FAIL_COND_V(!source, SOURCE_INVALID_VOICE);
@@ -400,23 +401,33 @@ SpatialSoundServer::SourceVoiceID SpatialSoundServerSW::source_play_sample(RID p
if (p_voice == SOURCE_NEXT_VOICE) {
const int num_voices = source->voices.size();
bool free_found = false;
+ int lowest_priority_voice = 0;
+ int lowest_priority = 0x7FFFFFFF;
for (int i = 0; i < num_voices; i++) {
const int candidate = (source->last_voice + 1 + i) % num_voices;
- if (!source->voices[candidate].active && !source->voices[candidate].restart) {
+ const Source::Voice &v = source->voices[candidate];
+ if (!v.active && !v.restart) {
free_found = true;
to_play = candidate;
break;
}
+ if (v.priority < lowest_priority) {
+ lowest_priority = v.priority;
+ lowest_priority_voice = candidate;
+ }
}
if (!free_found)
to_play = (source->last_voice + 1) % num_voices;
-
} else
to_play = p_voice;
ERR_FAIL_INDEX_V(to_play, source->voices.size(), SOURCE_INVALID_VOICE);
+ if ((source->voices[to_play].active || source->voices[to_play].restart) && source->voices[to_play].priority > p_priority)
+ return SOURCE_INVALID_VOICE;
+
source->voices[to_play].restart = true;
+ source->voices[to_play].priority = p_priority;
source->voices[to_play].sample_rid = p_sample;
source->voices[to_play].sample_mix_rate = p_mix_rate;
source->voices[to_play].pitch_scale = 1;
diff --git a/servers/spatial_sound/spatial_sound_server_sw.h b/servers/spatial_sound/spatial_sound_server_sw.h
index e05b78a9410..54f276ede6a 100644
--- a/servers/spatial_sound/spatial_sound_server_sw.h
+++ b/servers/spatial_sound/spatial_sound_server_sw.h
@@ -101,6 +101,7 @@ class SpatialSoundServerSW : public SpatialSoundServer {
RID sample_rid;
bool active;
bool restart;
+ int priority;
float pitch_scale;
float volume_scale;
int sample_mix_rate;
@@ -226,7 +227,7 @@ public:
virtual float source_get_param(RID p_source, SourceParam p_param) const;
virtual void source_set_audio_stream(RID p_source, AudioServer::AudioStream *p_stream); //null to unset
- virtual SourceVoiceID source_play_sample(RID p_source, RID p_sample, int p_mix_rate, int p_voice = SOURCE_NEXT_VOICE);
+ virtual SourceVoiceID source_play_sample(RID p_source, RID p_sample, int p_mix_rate, int p_voice = SOURCE_NEXT_VOICE, int p_priority = 0);
/* VOICES */
virtual void source_voice_set_pitch_scale(RID p_source, SourceVoiceID p_voice, float p_pitch_scale);
virtual void source_voice_set_volume_scale_db(RID p_source, SourceVoiceID p_voice, float p_volume);
diff --git a/servers/spatial_sound_2d/spatial_sound_2d_server_sw.cpp b/servers/spatial_sound_2d/spatial_sound_2d_server_sw.cpp
index f9ec253c0c6..6f0ae891012 100644
--- a/servers/spatial_sound_2d/spatial_sound_2d_server_sw.cpp
+++ b/servers/spatial_sound_2d/spatial_sound_2d_server_sw.cpp
@@ -94,6 +94,7 @@ SpatialSound2DServerSW::Source::Voice::Voice() {
active = false;
restart = false;
+ priority = 0;
pitch_scale = 1.0;
volume_scale = 0.0;
voice_rid = AudioServer::get_singleton()->voice_create();
@@ -387,7 +388,7 @@ void SpatialSound2DServerSW::source_set_audio_stream(RID p_source, AudioServer::
} //null to unset
-SpatialSound2DServer::SourceVoiceID SpatialSound2DServerSW::source_play_sample(RID p_source, RID p_sample, int p_mix_rate, int p_voice) {
+SpatialSound2DServer::SourceVoiceID SpatialSound2DServerSW::source_play_sample(RID p_source, RID p_sample, int p_mix_rate, int p_voice, int p_priority) {
Source *source = source_owner.get(p_source);
ERR_FAIL_COND_V(!source, SOURCE_INVALID_VOICE);
@@ -397,23 +398,33 @@ SpatialSound2DServer::SourceVoiceID SpatialSound2DServerSW::source_play_sample(R
if (p_voice == SOURCE_NEXT_VOICE) {
const int num_voices = source->voices.size();
bool free_found = false;
+ int lowest_priority_voice = 0;
+ int lowest_priority = 0x7FFFFFFF;
for (int i = 0; i < num_voices; i++) {
const int candidate = (source->last_voice + 1 + i) % num_voices;
- if (!source->voices[candidate].active && !source->voices[candidate].restart) {
+ const Source::Voice &v = source->voices[candidate];
+ if (!v.active && !v.restart) {
free_found = true;
to_play = candidate;
break;
}
+ if (v.priority < lowest_priority) {
+ lowest_priority = v.priority;
+ lowest_priority_voice = candidate;
+ }
}
if (!free_found)
to_play = (source->last_voice + 1) % num_voices;
-
} else
to_play = p_voice;
ERR_FAIL_INDEX_V(to_play, source->voices.size(), SOURCE_INVALID_VOICE);
+ if ((source->voices[to_play].active || source->voices[to_play].restart) && source->voices[to_play].priority > p_priority)
+ return SOURCE_INVALID_VOICE;
+
source->voices[to_play].restart = true;
+ source->voices[to_play].priority = p_priority;
source->voices[to_play].sample_rid = p_sample;
source->voices[to_play].sample_mix_rate = p_mix_rate;
source->voices[to_play].pitch_scale = 1;
diff --git a/servers/spatial_sound_2d/spatial_sound_2d_server_sw.h b/servers/spatial_sound_2d/spatial_sound_2d_server_sw.h
index acc70e69c47..de4cfee68f8 100644
--- a/servers/spatial_sound_2d/spatial_sound_2d_server_sw.h
+++ b/servers/spatial_sound_2d/spatial_sound_2d_server_sw.h
@@ -100,6 +100,7 @@ class SpatialSound2DServerSW : public SpatialSound2DServer {
RID sample_rid;
bool active;
bool restart;
+ int priority;
float pitch_scale;
float volume_scale;
int sample_mix_rate;
@@ -225,7 +226,7 @@ public:
virtual float source_get_param(RID p_source, SourceParam p_param) const;
virtual void source_set_audio_stream(RID p_source, AudioServer::AudioStream *p_stream); //null to unset
- virtual SourceVoiceID source_play_sample(RID p_source, RID p_sample, int p_mix_rate, int p_voice = SOURCE_NEXT_VOICE);
+ virtual SourceVoiceID source_play_sample(RID p_source, RID p_sample, int p_mix_rate, int p_voice = SOURCE_NEXT_VOICE, int p_priority = 0);
/* VOICES */
virtual void source_voice_set_pitch_scale(RID p_source, SourceVoiceID p_voice, float p_pitch_scale);
virtual void source_voice_set_volume_scale_db(RID p_source, SourceVoiceID p_voice, float p_volume);
diff --git a/servers/spatial_sound_2d_server.h b/servers/spatial_sound_2d_server.h
index 7c577e8bec5..08833287e12 100644
--- a/servers/spatial_sound_2d_server.h
+++ b/servers/spatial_sound_2d_server.h
@@ -117,7 +117,7 @@ public:
virtual float source_get_param(RID p_source, SourceParam p_param) const = 0;
virtual void source_set_audio_stream(RID p_source, AudioServer::AudioStream *p_stream) = 0; //null to unset
- virtual SourceVoiceID source_play_sample(RID p_source, RID p_sample, int p_mix_rate, int p_voice = SOURCE_NEXT_VOICE) = 0;
+ virtual SourceVoiceID source_play_sample(RID p_source, RID p_sample, int p_mix_rate, int p_voice = SOURCE_NEXT_VOICE, int p_priority = 0) = 0;
//voices
virtual void source_voice_set_pitch_scale(RID p_source, SourceVoiceID p_voice, float p_pitch_scale) = 0;
virtual void source_voice_set_volume_scale_db(RID p_source, SourceVoiceID p_voice, float p_volume_db) = 0;
diff --git a/servers/spatial_sound_server.h b/servers/spatial_sound_server.h
index 72d3ae0af03..be37f9b5093 100644
--- a/servers/spatial_sound_server.h
+++ b/servers/spatial_sound_server.h
@@ -121,7 +121,7 @@ public:
virtual float source_get_param(RID p_source, SourceParam p_param) const = 0;
virtual void source_set_audio_stream(RID p_source, AudioServer::AudioStream *p_stream) = 0; //null to unset
- virtual SourceVoiceID source_play_sample(RID p_source, RID p_sample, int p_mix_rate, int p_voice = SOURCE_NEXT_VOICE) = 0;
+ virtual SourceVoiceID source_play_sample(RID p_source, RID p_sample, int p_mix_rate, int p_voice = SOURCE_NEXT_VOICE, int p_priority = 0) = 0;
//voices
virtual void source_voice_set_pitch_scale(RID p_source, SourceVoiceID p_voice, float p_pitch_scale) = 0;
virtual void source_voice_set_volume_scale_db(RID p_source, SourceVoiceID p_voice, float p_volume_db) = 0;