Sfoglia il codice sorgente

Merge pull request #8294 from RandomShaper/sample-players-priority-2.1

Add priority to samples in a library (2.1)
Rémi Verschelde 8 anni fa
parent
commit
f7c3ecb38c

+ 19 - 0
doc/base/classes.xml

@@ -33677,6 +33677,7 @@
 	</brief_description>
 	<description>
 		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.
 	</description>
 	<methods>
 		<method name="add_sample">
@@ -33737,6 +33738,15 @@
 				Return the volume (in dB) for the given sample.
 			</description>
 		</method>
+		<method name="sample_get_priority" qualifiers="const">
+			<return type="int">
+			</return>
+			<argument index="0" name="name" type="String">
+			</argument>
+			<description>
+				Return the priority for the given sample.
+			</description>
+		</method>
 		<method name="sample_set_pitch_scale">
 			<argument index="0" name="name" type="String">
 			</argument>
@@ -33755,6 +33765,15 @@
 				Set the volume (in dB) for the given sample.
 			</description>
 		</method>
+		<method name="sample_set_priority">
+			<argument index="0" name="name" type="String">
+			</argument>
+			<argument index="1" name="priority" type="int">
+			</argument>
+			<description>
+				Set the priority for the given sample.
+			</description>
+		</method>
 	</methods>
 	<constants>
 	</constants>

+ 20 - 5
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);
 

+ 2 - 1
scene/2d/sample_player_2d.cpp

@@ -130,8 +130,9 @@ SamplePlayer2D::VoiceID SamplePlayer2D::play(const String &p_sample, int p_voice
 	Ref<Sample> 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);
 

+ 1 - 0
scene/3d/spatial_sample_player.cpp

@@ -130,6 +130,7 @@ SpatialSamplePlayer::VoiceID SpatialSamplePlayer::play(const String &p_sample, i
 	Ref<Sample> 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)

+ 17 - 1
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> 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;

+ 1 - 0
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;

+ 18 - 0
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<StringName> 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() {

+ 4 - 0
scene/resources/sample_library.h

@@ -42,10 +42,12 @@ class SampleLibrary : public Resource {
 		Ref<Sample> 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<Sample> get_sample(const StringName &p_name) const;
 	void get_sample_list(List<StringName> *p_samples) const;
 	void remove_sample(const StringName &p_name);

+ 14 - 3
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;

+ 2 - 1
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);

+ 14 - 3
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;

+ 2 - 1
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);

+ 1 - 1
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;

+ 1 - 1
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;