Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions doc/classes/AudioServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,26 @@
Generates an [AudioBusLayout] using the available buses and effects.
</description>
</method>
<method name="get_absolute_time" qualifiers="const">
<return type="float" />
<description>
Returns the absolute time in seconds of the [AudioServer] timeline based on the number of audio frames mixed. Used to schedule sounds to be played in the future with higher accuracy.
[b]Note:[/b] This value only updates each time an audio chunk is mixed and should not be relied on as an accurate "current" time of the [AudioServer].
[b]Example:[/b] Schedule two sounds to be played at the same time ~1 second in the future:
[codeblocks]
[gdscript]
var future_time = AudioServer.get_absolute_time() + 1
player1.play_scheduled(future_time)
player2.play_scheduled(future_time)
[/gdscript]
[csharp]
double futureTime = AudioServer.GetAbsoluteTime() + 1;
player1.PlayScheduled(futureTime);
player2.PlayScheduled(futureTime);
[/csharp]
[/codeblocks]
</description>
</method>
<method name="get_bus_channels" qualifiers="const">
<return type="int" />
<param index="0" name="bus_idx" type="int" />
Expand Down
12 changes: 12 additions & 0 deletions doc/classes/AudioStreamPlayer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@
Plays a sound from the beginning, or the given [param from_position] in seconds.
</description>
</method>
<method name="play_scheduled">
<return type="void" />
<param index="0" name="absolute_time" type="float" />
<param index="1" name="from_position" type="float" default="0.0" />
<description>
Schedules a sound to be played at [param absolute_time] on the [AudioServer] timeline. Use in conjunction with [method AudioServer.get_absolute_time]. The sound starts from the given [param from_position] in seconds.
[b]Note:[/b] Sounds scheduled to play earlier than [method AudioServer.get_absolute_time] will be played immediately.
[b]Note:[/b] By default, scheduled sounds will stop the currently playing sound on this player. Consider changing [member max_polyphony] to prevent this.
[b]Note:[/b] [member pitch_scale] does not affect the scheduling time.
[b]Note:[/b] On the Web platform, [member playback_type] must be set to [constant AudioServer.PLAYBACK_TYPE_STREAM] for [method play_scheduled] to work.
</description>
</method>
<method name="seek">
<return type="void" />
<param index="0" name="to_position" type="float" />
Expand Down
12 changes: 12 additions & 0 deletions doc/classes/AudioStreamPlayer2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@
Queues the audio to play on the next physics frame, from the given position [param from_position], in seconds.
</description>
</method>
<method name="play_scheduled">
<return type="void" />
<param index="0" name="absolute_time" type="float" />
<param index="1" name="from_position" type="float" default="0.0" />
<description>
Schedules a sound to be played at [param absolute_time] on the [AudioServer] timeline. Use in conjunction with [method AudioServer.get_absolute_time]. The sound starts from the given [param from_position] in seconds.
[b]Note:[/b] Sounds scheduled to play earlier than [method AudioServer.get_absolute_time] will be played immediately.
[b]Note:[/b] By default, scheduled sounds will stop the currently playing sound on this player. Consider changing [member max_polyphony] to prevent this.
[b]Note:[/b] [member pitch_scale] does not affect the scheduling time.
[b]Note:[/b] On the Web platform, [member playback_type] must be set to [constant AudioServer.PLAYBACK_TYPE_STREAM] for [method play_scheduled] to work.
</description>
</method>
<method name="seek">
<return type="void" />
<param index="0" name="to_position" type="float" />
Expand Down
12 changes: 12 additions & 0 deletions doc/classes/AudioStreamPlayer3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@
Queues the audio to play on the next physics frame, from the given position [param from_position], in seconds.
</description>
</method>
<method name="play_scheduled">
<return type="void" />
<param index="0" name="absolute_time" type="float" />
<param index="1" name="from_position" type="float" default="0.0" />
<description>
Schedules a sound to be played at [param absolute_time] on the [AudioServer] timeline. Use in conjunction with [method AudioServer.get_absolute_time]. The sound starts from the given [param from_position] in seconds.
[b]Note:[/b] Sounds scheduled to play earlier than [method AudioServer.get_absolute_time] will be played immediately.
[b]Note:[/b] By default, scheduled sounds will stop the currently playing sound on this player. Consider changing [member max_polyphony] to prevent this.
[b]Note:[/b] [member pitch_scale] does not affect the scheduling time.
[b]Note:[/b] On the Web platform, [member playback_type] must be set to [constant AudioServer.PLAYBACK_TYPE_STREAM] for [method play_scheduled] to work.
</description>
</method>
<method name="seek">
<return type="void" />
<param index="0" name="to_position" type="float" />
Expand Down
15 changes: 15 additions & 0 deletions misc/extension_api_validation/4.4-stable.expected
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,18 @@ Validate extension JSON: Error: Field 'classes/TextServerExtension/methods/_shap
Validate extension JSON: Error: Field 'classes/TextServerExtension/methods/_shaped_text_draw_outline/arguments': size changed value in new API, from 7 to 8.

Optional "oversmpling" argument added. Compatibility methods registered.


GH-105545
---------
Validate extension JSON: Error: Field 'classes/AudioStreamPlayer/methods/get_playback_position/return_value': meta changed value in new API, from "float" to "double".
Validate extension JSON: Error: Field 'classes/AudioStreamPlayer/methods/play/arguments/0': meta changed value in new API, from "float" to "double".
Validate extension JSON: Error: Field 'classes/AudioStreamPlayer/methods/seek/arguments/0': meta changed value in new API, from "float" to "double".
Validate extension JSON: Error: Field 'classes/AudioStreamPlayer2D/methods/get_playback_position/return_value': meta changed value in new API, from "float" to "double".
Validate extension JSON: Error: Field 'classes/AudioStreamPlayer2D/methods/play/arguments/0': meta changed value in new API, from "float" to "double".
Validate extension JSON: Error: Field 'classes/AudioStreamPlayer2D/methods/seek/arguments/0': meta changed value in new API, from "float" to "double".
Validate extension JSON: Error: Field 'classes/AudioStreamPlayer3D/methods/get_playback_position/return_value': meta changed value in new API, from "float" to "double".
Validate extension JSON: Error: Field 'classes/AudioStreamPlayer3D/methods/play/arguments/0': meta changed value in new API, from "float" to "double".
Validate extension JSON: Error: Field 'classes/AudioStreamPlayer3D/methods/seek/arguments/0': meta changed value in new API, from "float" to "double".

Playback position return/param type changed from float to double for higher precision. Compatibility methods registered.
15 changes: 15 additions & 0 deletions scene/2d/audio_stream_player_2d.compat.inc
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,23 @@ bool AudioStreamPlayer2D::_is_autoplay_enabled_bind_compat_86907() {
return is_autoplay_enabled();
}

void AudioStreamPlayer2D::_play_bind_compat_105545(float p_from_pos) {
play(p_from_pos);
}

void AudioStreamPlayer2D::_seek_bind_compat_105545(float p_seconds) {
seek(p_seconds);
}

float AudioStreamPlayer2D::_get_playback_position_bind_compat_105545() {
return get_playback_position();
}

void AudioStreamPlayer2D::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("is_autoplay_enabled"), &AudioStreamPlayer2D::_is_autoplay_enabled_bind_compat_86907);
ClassDB::bind_compatibility_method(D_METHOD("play", "from_position"), &AudioStreamPlayer2D::_play_bind_compat_105545, DEFVAL(0.0));
ClassDB::bind_compatibility_method(D_METHOD("seek", "to_position"), &AudioStreamPlayer2D::_seek_bind_compat_105545);
ClassDB::bind_compatibility_method(D_METHOD("get_playback_position"), &AudioStreamPlayer2D::_get_playback_position_bind_compat_105545);
}

#endif // DISABLE_DEPRECATED
23 changes: 19 additions & 4 deletions scene/2d/audio_stream_player_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ void AudioStreamPlayer2D::_notification(int p_what) {

if (setplayback.is_valid() && setplay.get() >= 0) {
internal->active.set();
AudioServer::get_singleton()->start_playback_stream(setplayback, _get_actual_bus(), volume_vector, setplay.get(), internal->pitch_scale);
AudioServer::get_singleton()->start_playback_stream(setplayback, _get_actual_bus(), volume_vector, setplay.get(), internal->scheduled_time, internal->pitch_scale);
setplayback.unref();
setplay.set(-1);
}
Expand Down Expand Up @@ -231,7 +231,7 @@ float AudioStreamPlayer2D::get_pitch_scale() const {
return internal->pitch_scale;
}

void AudioStreamPlayer2D::play(float p_from_pos) {
void AudioStreamPlayer2D::_play_internal(double p_from_pos) {
Ref<AudioStreamPlayback> stream_playback = internal->play_basic();
if (stream_playback.is_null()) {
return;
Expand All @@ -241,6 +241,10 @@ void AudioStreamPlayer2D::play(float p_from_pos) {

// Sample handling.
if (stream_playback->get_is_sample() && stream_playback->get_sample_playback().is_valid()) {
if (internal->scheduled_time > 0) {
WARN_PRINT_ED("play_scheduled() does not support samples. Playing immediately.");
}

Ref<AudioSamplePlayback> sample_playback = stream_playback->get_sample_playback();
sample_playback->offset = p_from_pos;
sample_playback->bus = _get_actual_bus();
Expand All @@ -249,7 +253,17 @@ void AudioStreamPlayer2D::play(float p_from_pos) {
}
}

void AudioStreamPlayer2D::seek(float p_seconds) {
void AudioStreamPlayer2D::play(double p_from_pos) {
internal->scheduled_time = 0;
_play_internal(p_from_pos);
}

void AudioStreamPlayer2D::play_scheduled(double p_abs_time, double p_from_pos) {
internal->scheduled_time = p_abs_time;
_play_internal(p_from_pos);
}

void AudioStreamPlayer2D::seek(double p_seconds) {
internal->seek(p_seconds);
}

Expand All @@ -265,7 +279,7 @@ bool AudioStreamPlayer2D::is_playing() const {
return internal->is_playing();
}

float AudioStreamPlayer2D::get_playback_position() {
double AudioStreamPlayer2D::get_playback_position() {
if (setplay.get() >= 0) {
return setplay.get(); // play() has been called this frame, but no playback exists just yet.
}
Expand Down Expand Up @@ -388,6 +402,7 @@ void AudioStreamPlayer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_pitch_scale"), &AudioStreamPlayer2D::get_pitch_scale);

ClassDB::bind_method(D_METHOD("play", "from_position"), &AudioStreamPlayer2D::play, DEFVAL(0.0));
ClassDB::bind_method(D_METHOD("play_scheduled", "absolute_time", "from_position"), &AudioStreamPlayer2D::play_scheduled, DEFVAL(0.0));
ClassDB::bind_method(D_METHOD("seek", "to_position"), &AudioStreamPlayer2D::seek);
ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayer2D::stop);

Expand Down
12 changes: 9 additions & 3 deletions scene/2d/audio_stream_player_2d.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ class AudioStreamPlayer2D : public Node2D {
StringName _get_actual_bus();
void _update_panning();

void _play_internal(double p_from_pos = 0.0);

static void _listener_changed_cb(void *self) { reinterpret_cast<AudioStreamPlayer2D *>(self)->force_update_panning = true; }

uint32_t area_mask = 1;
Expand All @@ -93,6 +95,9 @@ class AudioStreamPlayer2D : public Node2D {

#ifndef DISABLE_DEPRECATED
bool _is_autoplay_enabled_bind_compat_86907();
void _play_bind_compat_105545(float p_from_pos = 0.0);
void _seek_bind_compat_105545(float p_seconds);
float _get_playback_position_bind_compat_105545();
static void _bind_compatibility_methods();
#endif // DISABLE_DEPRECATED

Expand All @@ -109,11 +114,12 @@ class AudioStreamPlayer2D : public Node2D {
void set_pitch_scale(float p_pitch_scale);
float get_pitch_scale() const;

void play(float p_from_pos = 0.0);
void seek(float p_seconds);
void play(double p_from_pos = 0.0);
void play_scheduled(double p_abs_time, double p_from_pos = 0.0);
void seek(double p_seconds);
void stop();
bool is_playing() const;
float get_playback_position();
double get_playback_position();

void set_bus(const StringName &p_bus);
StringName get_bus() const;
Expand Down
15 changes: 15 additions & 0 deletions scene/3d/audio_stream_player_3d.compat.inc
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,23 @@ bool AudioStreamPlayer3D::_is_autoplay_enabled_bind_compat_86907() {
return is_autoplay_enabled();
}

void AudioStreamPlayer3D::_play_bind_compat_105545(float p_from_pos) {
play(p_from_pos);
}

void AudioStreamPlayer3D::_seek_bind_compat_105545(float p_seconds) {
seek(p_seconds);
}

float AudioStreamPlayer3D::_get_playback_position_bind_compat_105545() {
return get_playback_position();
}

void AudioStreamPlayer3D::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("is_autoplay_enabled"), &AudioStreamPlayer3D::_is_autoplay_enabled_bind_compat_86907);
ClassDB::bind_compatibility_method(D_METHOD("play", "from_position"), &AudioStreamPlayer3D::_play_bind_compat_105545, DEFVAL(0.0));
ClassDB::bind_compatibility_method(D_METHOD("seek", "to_position"), &AudioStreamPlayer3D::_seek_bind_compat_105545);
ClassDB::bind_compatibility_method(D_METHOD("get_playback_position"), &AudioStreamPlayer3D::_get_playback_position_bind_compat_105545);
}

#endif // DISABLE_DEPRECATED
23 changes: 19 additions & 4 deletions scene/3d/audio_stream_player_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
internal->active.set();
HashMap<StringName, Vector<AudioFrame>> bus_map;
bus_map[_get_actual_bus()] = volume_vector;
AudioServer::get_singleton()->start_playback_stream(setplayback, bus_map, setplay.get(), actual_pitch_scale, linear_attenuation, attenuation_filter_cutoff_hz);
AudioServer::get_singleton()->start_playback_stream(setplayback, bus_map, setplay.get(), internal->scheduled_time, actual_pitch_scale, linear_attenuation, attenuation_filter_cutoff_hz);
setplayback.unref();
setplay.set(-1);
}
Expand Down Expand Up @@ -591,7 +591,7 @@ float AudioStreamPlayer3D::get_pitch_scale() const {
return internal->pitch_scale;
}

void AudioStreamPlayer3D::play(float p_from_pos) {
void AudioStreamPlayer3D::_play_internal(double p_from_pos) {
Ref<AudioStreamPlayback> stream_playback = internal->play_basic();
if (stream_playback.is_null()) {
return;
Expand All @@ -601,6 +601,10 @@ void AudioStreamPlayer3D::play(float p_from_pos) {

// Sample handling.
if (stream_playback->get_is_sample() && stream_playback->get_sample_playback().is_valid()) {
if (internal->scheduled_time > 0) {
WARN_PRINT_ED("play_scheduled() does not support samples. Playing immediately.");
}

Ref<AudioSamplePlayback> sample_playback = stream_playback->get_sample_playback();
sample_playback->offset = p_from_pos;
sample_playback->bus = _get_actual_bus();
Expand All @@ -609,7 +613,17 @@ void AudioStreamPlayer3D::play(float p_from_pos) {
}
}

void AudioStreamPlayer3D::seek(float p_seconds) {
void AudioStreamPlayer3D::play(double p_from_pos) {
internal->scheduled_time = 0;
_play_internal(p_from_pos);
}

void AudioStreamPlayer3D::play_scheduled(double p_abs_time, double p_from_pos) {
internal->scheduled_time = p_abs_time;
_play_internal(p_from_pos);
}

void AudioStreamPlayer3D::seek(double p_seconds) {
internal->seek(p_seconds);
}

Expand All @@ -625,7 +639,7 @@ bool AudioStreamPlayer3D::is_playing() const {
return internal->is_playing();
}

float AudioStreamPlayer3D::get_playback_position() {
double AudioStreamPlayer3D::get_playback_position() {
if (setplay.get() >= 0) {
return setplay.get(); // play() has been called this frame, but no playback exists just yet.
}
Expand Down Expand Up @@ -822,6 +836,7 @@ void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_pitch_scale"), &AudioStreamPlayer3D::get_pitch_scale);

ClassDB::bind_method(D_METHOD("play", "from_position"), &AudioStreamPlayer3D::play, DEFVAL(0.0));
ClassDB::bind_method(D_METHOD("play_scheduled", "absolute_time", "from_position"), &AudioStreamPlayer3D::play_scheduled, DEFVAL(0.0));
ClassDB::bind_method(D_METHOD("seek", "to_position"), &AudioStreamPlayer3D::seek);
ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayer3D::stop);

Expand Down
12 changes: 9 additions & 3 deletions scene/3d/audio_stream_player_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ class AudioStreamPlayer3D : public Node3D {
#endif // PHYSICS_3D_DISABLED
Vector<AudioFrame> _update_panning();

void _play_internal(double p_from_pos = 0.0);

uint32_t area_mask = 1;

AudioServer::PlaybackType playback_type = AudioServer::PlaybackType::PLAYBACK_TYPE_DEFAULT;
Expand Down Expand Up @@ -132,6 +134,9 @@ class AudioStreamPlayer3D : public Node3D {

#ifndef DISABLE_DEPRECATED
bool _is_autoplay_enabled_bind_compat_86907();
void _play_bind_compat_105545(float p_from_pos = 0.0);
void _seek_bind_compat_105545(float p_seconds);
float _get_playback_position_bind_compat_105545();
static void _bind_compatibility_methods();
#endif // DISABLE_DEPRECATED

Expand All @@ -154,11 +159,12 @@ class AudioStreamPlayer3D : public Node3D {
void set_pitch_scale(float p_pitch_scale);
float get_pitch_scale() const;

void play(float p_from_pos = 0.0);
void seek(float p_seconds);
void play(double p_from_pos = 0.0);
void play_scheduled(double p_abs_time, double p_from_pos = 0.0);
void seek(double p_seconds);
void stop();
bool is_playing() const;
float get_playback_position();
double get_playback_position();

void set_bus(const StringName &p_bus);
StringName get_bus() const;
Expand Down
15 changes: 15 additions & 0 deletions scene/audio/audio_stream_player.compat.inc
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,23 @@ bool AudioStreamPlayer::_is_autoplay_enabled_bind_compat_86907() {
return is_autoplay_enabled();
}

void AudioStreamPlayer::_play_bind_compat_105545(float p_from_pos) {
play(p_from_pos);
}

void AudioStreamPlayer::_seek_bind_compat_105545(float p_seconds) {
seek(p_seconds);
}

float AudioStreamPlayer::_get_playback_position_bind_compat_105545() {
return get_playback_position();
}

void AudioStreamPlayer::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("is_autoplay_enabled"), &AudioStreamPlayer::_is_autoplay_enabled_bind_compat_86907);
ClassDB::bind_compatibility_method(D_METHOD("play", "from_position"), &AudioStreamPlayer::_play_bind_compat_105545, DEFVAL(0.0));
ClassDB::bind_compatibility_method(D_METHOD("seek", "to_position"), &AudioStreamPlayer::_seek_bind_compat_105545);
ClassDB::bind_compatibility_method(D_METHOD("get_playback_position"), &AudioStreamPlayer::_get_playback_position_bind_compat_105545);
}

#endif // DISABLE_DEPRECATED
Loading