Add priority to samples in a library

This commit is contained in:
Pedro J. Estébanez 2017-04-06 19:00:19 +02:00
parent 3916d964de
commit 9f8f8efa67
14 changed files with 116 additions and 17 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -74,6 +74,7 @@ private:
uint32_t check;
bool active;
int priority;
int sample_mix_rate;
int mix_rate;
float volume;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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