DynamicSound.ReverbTail now drives a seamless transition: when the current
song is within ReverbTail seconds of its full length, the next song is started
so its opening covers the outgoing tail. Both songs are audible during the
overlap; the outgoing one stops when its full length has elapsed.
API changes (continuous players only):
- Replaces `Loop : bool` with `LoopMode : enum { Single, All }`. Single keeps
repeating the current song; All advances through the playlist and wraps
back to index 0. There is no longer a "play once and stop" mode.
- The playlist resource is no longer mutated. The player tracks an internal
index instead of popping songs off the front.
- Adds `get_current_song_index() -> int`, `advance_to_next_song()`, and
`advance_to_track(index: int)` on each continuous wrapper. Both advance
methods accelerate the outgoing song so its remaining time hits ReverbTail
immediately, giving a smooth transition rather than a hard cut.
Internals: DynamicSoundPlayerCore now keeps an `_active_songs` array of an
inner _ActiveSong record (ids, start_time, song_length, reverb_tail,
started_next). _process advances time globally and runs the start-next /
stop-old conditions per active song, mirroring the OvaniPlayer reference.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
Adds default_bus_layout.tres at the addon root containing a Music bus and an
FX bus, each routing into Master. Users can point Project Settings → Audio →
Default Bus Layout at this file (or copy it to their project root) to get the
buses the players auto-route to in the editor. README documents the wiring.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The continuous music players had PitchMode/RandomMin/MaxPitchScale exports but
no logic referenced them. Pitch variation only makes sense per-trigger, which
the FX family supports natively. So:
- Remove PitchMode, RandomMinPitchScale, RandomMaxPitchScale, and the
_validate_property hook from DynamicSoundPlayer / 2D / 3D.
- Add the same exports + _validate_property to DynamicSoundFXPlayer / 2D / 3D.
- Implement pitch resolution in DynamicSoundFXPlayerCore.play_fx: each trigger
samples a fresh pitch from PitchMode and passes it as the pitch_scale
argument to AudioStreamPlaybackPolyphonic.play_stream.
- Random pitch uses 1.0 + randf_range(min, max) so the existing -0.5/0.5
defaults give a useful [0.5, 1.5] pitch range.
- README updated to reflect the move.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When a player enters the tree in the editor, if its bus is still the default
"Master" and a "Music" (or "FX") bus exists in the AudioServer, switch to that.
User-customised buses are not overridden.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>