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
parent 36350ab8d5
commit e8224e3913
No known key found for this signature in database
GPG Key ID: A9EB2589C60F7268
5 changed files with 33 additions and 11 deletions

View File

@ -72,15 +72,16 @@ When the node enters the tree in the editor, `stream` is auto-assigned an `Audio
| 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. |
| `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. |
| `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. |
#### 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.
- **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.

View File

@ -45,6 +45,10 @@ func _ready() -> void:
func _process(delta: float) -> void:
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.
func pause() -> void:
if _core: _core.pause();

View File

@ -44,6 +44,10 @@ func _ready() -> void:
func _process(delta: float) -> void:
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.
func pause() -> void:
if _core: _core.pause();

View File

@ -44,6 +44,10 @@ func _ready() -> void:
func _process(delta: float) -> void:
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.
func pause() -> void:
if _core: _core.pause();

View File

@ -31,12 +31,26 @@ func _init(player) -> void:
func ready() -> void:
if Engine.is_editor_hint():
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;
if playlist == null or playlist.QueuedSongs.is_empty():
return;
_player.play();
_playback = _player.get_stream_playback();
_play_song(playlist.QueuedSongs[0]);
if _playback == null:
_player.play();
_playback = _player.get_stream_playback();
if Ids.is_empty():
_play_song(playlist.QueuedSongs[0]);
func process(delta: float) -> void:
if Engine.is_editor_hint():
@ -88,14 +102,9 @@ func is_song_playing() -> bool:
return not Ids.is_empty() and not _paused;
func fade_in(duration: float) -> void:
if _playback == null:
_player.play();
_playback = _player.get_stream_playback();
_start_playback();
if _paused:
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);
func fade_out(duration: float) -> void: