logo.jpg displays at the top of README.md. gd-dynamic-sound-icon.jpg replaces
the icon.svg placeholder for the @icon decorator on all six player wrappers
plus the DynamicSound and DynamicSoundPlaylist resources.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
plugin.gd now checks Engine.get_version_info() in _enter_tree and pushes a
loud error if the engine is older than 4.6. Doesn't actually disable the
addon's class_names (Godot parses those independently of EditorPlugin), but
gives users a clear "this is the cause" signal before any cryptic downstream
errors land.
Also removes four add_autoload_singleton calls for gd-options-owned scripts
(GameSettings, InputSettings, GraphicsSettings, AudioSettings). They were
copy-paste leftovers from when this addon was forked; gd-options/plugin.gd
already registers them, so this addon was double-registering — gd-dynamic-
sound has no business owning those autoloads.
README documents the 4.6 requirement near the top.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The three IntensityN streams of a DynamicSound play in parallel, and the
player keys end-of-song timing off Intensity1's length — mismatched lengths
cause silent gaps in the higher intensity layers and broken advancement.
DynamicSound:
- Setters on Intensity1/2/3 push_warning when assigning a stream whose length
doesn't match the others (editor-time feedback).
- Public has_matching_layer_lengths() -> bool for callers wanting to validate
songs themselves.
DynamicSoundPlayerCore:
- _start_song_at_index pushes a runtime error if the song fails the check
before queuing its layers on the polyphonic playback.
The FX core deliberately doesn't add a runtime check — play_fx fires per
trigger and would spam, while the editor warning already covers authoring
mistakes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>
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>