Commit Graph
6 Commits
Author SHA1 Message Date
Daniel SamsonandClaude Opus 4.7 df3e73b32e add SkipMode enum (UseReverbTail / CrossFade / Jump)
advance_to_next_song / advance_to_track now branch on the new SkipMode export:

- UseReverbTail (default): existing behavior. Accelerate the outgoing song so
  remaining time hits ReverbTail, both songs play during the overlap, outgoing
  stops naturally.
- CrossFade: programmatic volume crossfade. Outgoing fades from current volume
  to silent over CrossFadeDuration seconds (then stops), incoming starts silent
  and fades up to full over the same duration. Independent of any global fade.
- Jump: hard cut. Outgoing song's streams are stopped immediately and removed
  from the active list before the incoming starts.

For CrossFade we needed per-song fade state (the global _fade_db can't drive
two songs in opposite directions at once), so _ActiveSong gained fade_db /
fade_from_db / fade_to_db / fade_duration / fade_elapsed / fading /
stop_after_fade fields. _apply_volumes_to_song now adds both the global and
per-song fade_db to volume_db; process() advances each song's fade per-frame
and stops songs whose fades reach the silent target with stop_after_fade set.

CrossFadeDuration is hidden in the inspector via _validate_property unless
SkipMode == CrossFade. The natural end-of-song advance is unchanged — it still
uses the song's reverb tail. SkipMode only affects programmatic skips.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 16:31:37 +01:00
Daniel SamsonandClaude Opus 4.7 c989fc4eea implement reverb tail, LoopMode, and playlist navigation
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>
2026-04-29 16:07:06 +01:00
Daniel SamsonandClaude Opus 4.7 e8224e3913 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>
2026-04-29 15:29:08 +01:00
Daniel SamsonandClaude Opus 4.7 dd805a4cd9 move PitchMode to FX players and implement random pitch
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>
2026-04-29 15:03:03 +01:00
Daniel SamsonandClaude Opus 4.7 7f227acb6a auto-detect Music/FX bus in editor
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>
2026-04-29 15:00:56 +01:00
Daniel SamsonandClaude Opus 4.7 cb47d89377 Initial commit: dynamic music & FX players
Continuous music players (DynamicSoundPlayer, 2D, 3D) with intensity-blended
layers, playlist queue, Loop, fade in/out, pause/resume. One-shot SFX players
(DynamicSoundFXPlayer, 2D, 3D) for overlapping triggers. All variants share
RefCounted core classes via duck-typed property access.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 14:46:48 +01:00