You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-04 12:00:25 +00:00
Simplify AudioStreamPolyphonic
* Make AudioStreamPolyphonic not requre a polling thread (simpler, faster) * Improve error reporting in AudioStreamPlayer*::get_stream_playback() error reporting to improve usability.
This commit is contained in:
@@ -391,10 +391,8 @@ bool AudioStreamPlayer2D::get_stream_paused() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ref<AudioStreamPlayback> AudioStreamPlayer2D::get_stream_playback() {
|
Ref<AudioStreamPlayback> AudioStreamPlayer2D::get_stream_playback() {
|
||||||
if (!stream_playbacks.is_empty()) {
|
ERR_FAIL_COND_V_MSG(stream_playbacks.is_empty(), Ref<AudioStreamPlayback>(), "Player is inactive. Call play() before requesting get_stream_playback().");
|
||||||
return stream_playbacks[stream_playbacks.size() - 1];
|
return stream_playbacks[stream_playbacks.size() - 1];
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioStreamPlayer2D::set_max_polyphony(int p_max_polyphony) {
|
void AudioStreamPlayer2D::set_max_polyphony(int p_max_polyphony) {
|
||||||
|
|||||||
@@ -784,10 +784,8 @@ bool AudioStreamPlayer3D::get_stream_paused() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ref<AudioStreamPlayback> AudioStreamPlayer3D::get_stream_playback() {
|
Ref<AudioStreamPlayback> AudioStreamPlayer3D::get_stream_playback() {
|
||||||
if (!stream_playbacks.is_empty()) {
|
ERR_FAIL_COND_V_MSG(stream_playbacks.is_empty(), Ref<AudioStreamPlayback>(), "Player is inactive. Call play() before requesting get_stream_playback().");
|
||||||
return stream_playbacks[stream_playbacks.size() - 1];
|
return stream_playbacks[stream_playbacks.size() - 1];
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioStreamPlayer3D::set_max_polyphony(int p_max_polyphony) {
|
void AudioStreamPlayer3D::set_max_polyphony(int p_max_polyphony) {
|
||||||
|
|||||||
@@ -308,10 +308,8 @@ void AudioStreamPlayer::_bus_layout_changed() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ref<AudioStreamPlayback> AudioStreamPlayer::get_stream_playback() {
|
Ref<AudioStreamPlayback> AudioStreamPlayer::get_stream_playback() {
|
||||||
if (!stream_playbacks.is_empty()) {
|
ERR_FAIL_COND_V_MSG(stream_playbacks.is_empty(), Ref<AudioStreamPlayback>(), "Player is inactive. Call play() before requesting get_stream_playback().");
|
||||||
return stream_playbacks[stream_playbacks.size() - 1];
|
return stream_playbacks[stream_playbacks.size() - 1];
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioStreamPlayer::_bind_methods() {
|
void AudioStreamPlayer::_bind_methods() {
|
||||||
|
|||||||
@@ -87,7 +87,6 @@ void AudioStreamPlaybackPolyphonic::stop() {
|
|||||||
AudioServer::get_singleton()->lock();
|
AudioServer::get_singleton()->lock();
|
||||||
}
|
}
|
||||||
s.active.clear();
|
s.active.clear();
|
||||||
s.finalizing.clear();
|
|
||||||
s.finish_request.clear();
|
s.finish_request.clear();
|
||||||
s.stream_playback.unref();
|
s.stream_playback.unref();
|
||||||
s.stream.unref();
|
s.stream.unref();
|
||||||
@@ -145,7 +144,6 @@ int AudioStreamPlaybackPolyphonic::mix(AudioFrame *p_buffer, float p_rate_scale,
|
|||||||
if (s.pending_play.is_set()) {
|
if (s.pending_play.is_set()) {
|
||||||
// Did not get the chance to play, was finalized too soon.
|
// Did not get the chance to play, was finalized too soon.
|
||||||
s.active.clear();
|
s.active.clear();
|
||||||
s.finalizing.set();
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
next_volume = 0;
|
next_volume = 0;
|
||||||
@@ -163,6 +161,8 @@ int AudioStreamPlaybackPolyphonic::mix(AudioFrame *p_buffer, float p_rate_scale,
|
|||||||
int offset = 0;
|
int offset = 0;
|
||||||
float volume = prev_volume;
|
float volume = prev_volume;
|
||||||
|
|
||||||
|
bool stream_done = false;
|
||||||
|
|
||||||
while (todo) {
|
while (todo) {
|
||||||
int to_mix = MIN(todo, int(INTERNAL_BUFFER_LEN));
|
int to_mix = MIN(todo, int(INTERNAL_BUFFER_LEN));
|
||||||
int mixed = s.stream_playback->mix(internal_buffer, s.pitch_scale, to_mix);
|
int mixed = s.stream_playback->mix(internal_buffer, s.pitch_scale, to_mix);
|
||||||
@@ -175,7 +175,7 @@ int AudioStreamPlaybackPolyphonic::mix(AudioFrame *p_buffer, float p_rate_scale,
|
|||||||
if (mixed < to_mix) {
|
if (mixed < to_mix) {
|
||||||
// Stream is done.
|
// Stream is done.
|
||||||
s.active.clear();
|
s.active.clear();
|
||||||
s.finalizing.set();
|
stream_done = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,34 +183,22 @@ int AudioStreamPlaybackPolyphonic::mix(AudioFrame *p_buffer, float p_rate_scale,
|
|||||||
offset += to_mix;
|
offset += to_mix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stream_done) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (s.finish_request.is_set()) {
|
if (s.finish_request.is_set()) {
|
||||||
s.active.clear();
|
s.active.clear();
|
||||||
s.finalizing.set();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return p_frames;
|
return p_frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioStreamPlaybackPolyphonic::_check_finalized_streams() {
|
|
||||||
if (!active) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Stream &s : streams) {
|
|
||||||
if (!s.active.is_set() && s.finalizing.is_set()) {
|
|
||||||
s.stream_playback.unref();
|
|
||||||
s.stream.unref();
|
|
||||||
s.finalizing.clear();
|
|
||||||
s.finish_request.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioStreamPlaybackPolyphonic::ID AudioStreamPlaybackPolyphonic::play_stream(const Ref<AudioStream> &p_stream, float p_from_offset, float p_volume_db, float p_pitch_scale) {
|
AudioStreamPlaybackPolyphonic::ID AudioStreamPlaybackPolyphonic::play_stream(const Ref<AudioStream> &p_stream, float p_from_offset, float p_volume_db, float p_pitch_scale) {
|
||||||
ERR_FAIL_COND_V(p_stream.is_null(), INVALID_ID);
|
ERR_FAIL_COND_V(p_stream.is_null(), INVALID_ID);
|
||||||
for (uint32_t i = 0; i < streams.size(); i++) {
|
for (uint32_t i = 0; i < streams.size(); i++) {
|
||||||
if (!streams[i].active.is_set() && !streams[i].finish_request.is_set() && !streams[i].finalizing.is_set()) {
|
if (!streams[i].active.is_set()) {
|
||||||
// Can use this stream, as it's not active.
|
// Can use this stream, as it's not active.
|
||||||
streams[i].stream = p_stream;
|
streams[i].stream = p_stream;
|
||||||
streams[i].stream_playback = streams[i].stream->instantiate_playback();
|
streams[i].stream_playback = streams[i].stream->instantiate_playback();
|
||||||
@@ -219,6 +207,7 @@ AudioStreamPlaybackPolyphonic::ID AudioStreamPlaybackPolyphonic::play_stream(con
|
|||||||
streams[i].prev_volume_db = p_volume_db;
|
streams[i].prev_volume_db = p_volume_db;
|
||||||
streams[i].pitch_scale = p_pitch_scale;
|
streams[i].pitch_scale = p_pitch_scale;
|
||||||
streams[i].id = id_counter++;
|
streams[i].id = id_counter++;
|
||||||
|
streams[i].finish_request.clear();
|
||||||
streams[i].pending_play.set();
|
streams[i].pending_play.set();
|
||||||
streams[i].active.set();
|
streams[i].active.set();
|
||||||
return (ID(i) << INDEX_SHIFT) | ID(streams[i].id);
|
return (ID(i) << INDEX_SHIFT) | ID(streams[i].id);
|
||||||
@@ -282,5 +271,4 @@ void AudioStreamPlaybackPolyphonic::_bind_methods() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AudioStreamPlaybackPolyphonic::AudioStreamPlaybackPolyphonic() {
|
AudioStreamPlaybackPolyphonic::AudioStreamPlaybackPolyphonic() {
|
||||||
SceneTree::get_singleton()->connect(SNAME("process_frame"), callable_mp(this, &AudioStreamPlaybackPolyphonic::_check_finalized_streams));
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ class AudioStreamPlaybackPolyphonic : public AudioStreamPlayback {
|
|||||||
SafeFlag active;
|
SafeFlag active;
|
||||||
SafeFlag pending_play;
|
SafeFlag pending_play;
|
||||||
SafeFlag finish_request;
|
SafeFlag finish_request;
|
||||||
SafeFlag finalizing;
|
|
||||||
float play_offset = 0;
|
float play_offset = 0;
|
||||||
float pitch_scale = 1.0;
|
float pitch_scale = 1.0;
|
||||||
Ref<AudioStream> stream;
|
Ref<AudioStream> stream;
|
||||||
@@ -73,7 +72,7 @@ class AudioStreamPlaybackPolyphonic : public AudioStreamPlayback {
|
|||||||
uint32_t id = 0;
|
uint32_t id = 0;
|
||||||
|
|
||||||
Stream() :
|
Stream() :
|
||||||
active(false), pending_play(false), finish_request(false), finalizing(false) {}
|
active(false), pending_play(false), finish_request(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
LocalVector<Stream> streams;
|
LocalVector<Stream> streams;
|
||||||
@@ -84,8 +83,6 @@ class AudioStreamPlaybackPolyphonic : public AudioStreamPlayback {
|
|||||||
|
|
||||||
_FORCE_INLINE_ Stream *_find_stream(int64_t p_id);
|
_FORCE_INLINE_ Stream *_find_stream(int64_t p_id);
|
||||||
|
|
||||||
void _check_finalized_streams();
|
|
||||||
|
|
||||||
friend class AudioStreamPolyphonic;
|
friend class AudioStreamPolyphonic;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
Reference in New Issue
Block a user