respect autoplay; add play_playlist() for manual start

DynamicSoundPlayerCore.ready() always called play() if a playlist had songs,
ignoring the inherited AudioStreamPlayer.autoplay property. Now early-returns
when autoplay is false. Adds play_playlist() (exposed on all three continuous
wrappers) so users with autoplay=false have a non-fade way to start playback.
fade_in() now uses the same _start_playback() helper.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Daniel Samson
2026-04-29 15:29:08 +01:00
co-authored by Claude Opus 4.7
parent 36350ab8d5
commit e8224e3913
5 changed files with 33 additions and 11 deletions
+3 -2
View File
@@ -72,15 +72,16 @@ When the node enters the tree in the editor, `stream` is auto-assigned an `Audio
| Method | Description | | Method | Description |
| --- | --- | | --- | --- |
| `play_playlist()` | Starts (or resumes) the playlist. Use this when `autoplay` is `false` and you want to start playback programmatically. |
| `pause()` | Pauses playback. No-op if not playing or already paused. | | `pause()` | Pauses playback. No-op if not playing or already paused. |
| `resume()` | Resumes playback after a pause. | | `resume()` | Resumes playback after a pause. |
| `is_song_playing() -> bool` | True iff a song's layers are active and not paused. Distinct from `is_playing()`, which stays true between songs because the polyphonic playback session itself is still live. | | `is_song_playing() -> bool` | True iff a song's layers are active and not paused. Distinct from `is_playing()`, which stays true between songs because the polyphonic playback session itself is still live. |
| `fade_in(duration: float)` | Starts playback (if needed), unpauses, and ramps volume from silent to `volume_db` over `duration` seconds. | | `fade_in(duration: float)` | Starts playback (if needed), unpauses, and ramps volume from silent to `volume_db` over `duration` seconds. Works regardless of `autoplay`. |
| `fade_out(duration: float)` | Ramps volume from current level to silent over `duration` seconds, then stops the polyphonic session. A subsequent `fade_in` reinitialises. | | `fade_out(duration: float)` | Ramps volume from current level to silent over `duration` seconds, then stops the polyphonic session. A subsequent `fade_in` reinitialises. |
#### Behaviour #### Behaviour
- **Autoplay.** On `_ready`, plays the front song of the playlist. - **Autoplay.** On `_ready`, plays the front song of the playlist *only if `autoplay` is true* (the inherited `AudioStreamPlayer.autoplay` property; default `true`). Set `autoplay = false` to defer playback to a `play_playlist()` or `fade_in()` call.
- **Advancement.** When a song's `Intensity1` length elapses, the player pops it from the queue and plays the next. With `Loop = true`, the popped song is re-appended to the back. - **Advancement.** When a song's `Intensity1` length elapses, the player pops it from the queue and plays the next. With `Loop = true`, the popped song is re-appended to the back.
- **Volume.** `volume_db` is honoured; the fade adjustment is layered on top internally, so manual volume changes during a fade still work correctly. - **Volume.** `volume_db` is honoured; the fade adjustment is layered on top internally, so manual volume changes during a fade still work correctly.
- **Editor.** All scripts are `@tool`, but `_ready` and `_process` early-return in the editor so audio doesn't play in the inspector. - **Editor.** All scripts are `@tool`, but `_ready` and `_process` early-return in the editor so audio doesn't play in the inspector.
+4
View File
@@ -45,6 +45,10 @@ func _ready() -> void:
func _process(delta: float) -> void: func _process(delta: float) -> void:
if _core: _core.process(delta); if _core: _core.process(delta);
## Start (or resume) playlist playback. Useful when [code]autoplay[/code] is false.
func play_playlist() -> void:
if _core: _core.play_playlist();
## Pause playback. Call [method resume] to continue. ## Pause playback. Call [method resume] to continue.
func pause() -> void: func pause() -> void:
if _core: _core.pause(); if _core: _core.pause();
+4
View File
@@ -44,6 +44,10 @@ func _ready() -> void:
func _process(delta: float) -> void: func _process(delta: float) -> void:
if _core: _core.process(delta); if _core: _core.process(delta);
## Start (or resume) playlist playback. Useful when [code]autoplay[/code] is false.
func play_playlist() -> void:
if _core: _core.play_playlist();
## Pause playback. Call [method resume] to continue. ## Pause playback. Call [method resume] to continue.
func pause() -> void: func pause() -> void:
if _core: _core.pause(); if _core: _core.pause();
+4
View File
@@ -44,6 +44,10 @@ func _ready() -> void:
func _process(delta: float) -> void: func _process(delta: float) -> void:
if _core: _core.process(delta); if _core: _core.process(delta);
## Start (or resume) playlist playback. Useful when [code]autoplay[/code] is false.
func play_playlist() -> void:
if _core: _core.play_playlist();
## Pause playback. Call [method resume] to continue. ## Pause playback. Call [method resume] to continue.
func pause() -> void: func pause() -> void:
if _core: _core.pause(); if _core: _core.pause();
+15 -6
View File
@@ -31,11 +31,25 @@ func _init(player) -> void:
func ready() -> void: func ready() -> void:
if Engine.is_editor_hint(): if Engine.is_editor_hint():
return; return;
if not _player.autoplay:
return;
_start_playback();
## Starts (or resumes) playlist playback. Useful when [code]autoplay[/code] is false.
func play_playlist() -> void:
if _paused:
resume();
return;
_start_playback();
func _start_playback() -> void:
var playlist : DynamicSoundPlaylist = _player.Playlist; var playlist : DynamicSoundPlaylist = _player.Playlist;
if playlist == null or playlist.QueuedSongs.is_empty(): if playlist == null or playlist.QueuedSongs.is_empty():
return; return;
if _playback == null:
_player.play(); _player.play();
_playback = _player.get_stream_playback(); _playback = _player.get_stream_playback();
if Ids.is_empty():
_play_song(playlist.QueuedSongs[0]); _play_song(playlist.QueuedSongs[0]);
func process(delta: float) -> void: func process(delta: float) -> void:
@@ -88,14 +102,9 @@ func is_song_playing() -> bool:
return not Ids.is_empty() and not _paused; return not Ids.is_empty() and not _paused;
func fade_in(duration: float) -> void: func fade_in(duration: float) -> void:
if _playback == null: _start_playback();
_player.play();
_playback = _player.get_stream_playback();
if _paused: if _paused:
resume(); resume();
var playlist : DynamicSoundPlaylist = _player.Playlist;
if Ids.is_empty() and playlist != null and not playlist.QueuedSongs.is_empty():
_play_song(playlist.QueuedSongs[0]);
_start_fade(_FADE_SILENT_DB, 0.0, duration, false); _start_fade(_FADE_SILENT_DB, 0.0, duration, false);
func fade_out(duration: float) -> void: func fade_out(duration: float) -> void: