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>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
7f227acb6a
commit
dd805a4cd9
@@ -15,6 +15,17 @@ extends AudioStreamPlayer
|
||||
## Volume mix between intensity layers. Only blended when all three layers are set.
|
||||
@export_range(0, 1) var Intensity : float = 0;
|
||||
|
||||
## How playback pitch is selected for each [method play_fx] trigger.
|
||||
@export var PitchMode : DynamicSoundConstants.PitchMode = DynamicSoundConstants.PitchMode.Constant:
|
||||
set(value):
|
||||
PitchMode = value;
|
||||
notify_property_list_changed();
|
||||
|
||||
## Minimum pitch offset (added to 1.0) when [member PitchMode] is Random.
|
||||
@export var RandomMinPitchScale : float = -0.5;
|
||||
## Maximum pitch offset (added to 1.0) when [member PitchMode] is Random.
|
||||
@export var RandomMaxPitchScale : float = 0.5;
|
||||
|
||||
var _core : DynamicSoundFXPlayerCore;
|
||||
|
||||
func _enter_tree() -> void:
|
||||
@@ -25,6 +36,11 @@ func _enter_tree() -> void:
|
||||
if bus == &"Master" and AudioServer.get_bus_index("FX") != -1:
|
||||
bus = "FX";
|
||||
|
||||
func _validate_property(property: Dictionary) -> void:
|
||||
if property.name in ["RandomMinPitchScale", "RandomMaxPitchScale"]:
|
||||
if PitchMode != DynamicSoundConstants.PitchMode.Random:
|
||||
property.usage &= ~PROPERTY_USAGE_EDITOR;
|
||||
|
||||
func _ready() -> void:
|
||||
_core = DynamicSoundFXPlayerCore.new(self);
|
||||
_core.ready();
|
||||
|
||||
@@ -14,6 +14,17 @@ extends AudioStreamPlayer2D
|
||||
## Volume mix between intensity layers. Only blended when all three layers are set.
|
||||
@export_range(0, 1) var Intensity : float = 0;
|
||||
|
||||
## How playback pitch is selected for each [method play_fx] trigger.
|
||||
@export var PitchMode : DynamicSoundConstants.PitchMode = DynamicSoundConstants.PitchMode.Constant:
|
||||
set(value):
|
||||
PitchMode = value;
|
||||
notify_property_list_changed();
|
||||
|
||||
## Minimum pitch offset (added to 1.0) when [member PitchMode] is Random.
|
||||
@export var RandomMinPitchScale : float = -0.5;
|
||||
## Maximum pitch offset (added to 1.0) when [member PitchMode] is Random.
|
||||
@export var RandomMaxPitchScale : float = 0.5;
|
||||
|
||||
var _core : DynamicSoundFXPlayerCore;
|
||||
|
||||
func _enter_tree() -> void:
|
||||
@@ -24,6 +35,11 @@ func _enter_tree() -> void:
|
||||
if bus == &"Master" and AudioServer.get_bus_index("FX") != -1:
|
||||
bus = "FX";
|
||||
|
||||
func _validate_property(property: Dictionary) -> void:
|
||||
if property.name in ["RandomMinPitchScale", "RandomMaxPitchScale"]:
|
||||
if PitchMode != DynamicSoundConstants.PitchMode.Random:
|
||||
property.usage &= ~PROPERTY_USAGE_EDITOR;
|
||||
|
||||
func _ready() -> void:
|
||||
_core = DynamicSoundFXPlayerCore.new(self);
|
||||
_core.ready();
|
||||
|
||||
@@ -14,6 +14,17 @@ extends AudioStreamPlayer3D
|
||||
## Volume mix between intensity layers. Only blended when all three layers are set.
|
||||
@export_range(0, 1) var Intensity : float = 0;
|
||||
|
||||
## How playback pitch is selected for each [method play_fx] trigger.
|
||||
@export var PitchMode : DynamicSoundConstants.PitchMode = DynamicSoundConstants.PitchMode.Constant:
|
||||
set(value):
|
||||
PitchMode = value;
|
||||
notify_property_list_changed();
|
||||
|
||||
## Minimum pitch offset (added to 1.0) when [member PitchMode] is Random.
|
||||
@export var RandomMinPitchScale : float = -0.5;
|
||||
## Maximum pitch offset (added to 1.0) when [member PitchMode] is Random.
|
||||
@export var RandomMaxPitchScale : float = 0.5;
|
||||
|
||||
var _core : DynamicSoundFXPlayerCore;
|
||||
|
||||
func _enter_tree() -> void:
|
||||
@@ -24,6 +35,11 @@ func _enter_tree() -> void:
|
||||
if bus == &"Master" and AudioServer.get_bus_index("FX") != -1:
|
||||
bus = "FX";
|
||||
|
||||
func _validate_property(property: Dictionary) -> void:
|
||||
if property.name in ["RandomMinPitchScale", "RandomMaxPitchScale"]:
|
||||
if PitchMode != DynamicSoundConstants.PitchMode.Random:
|
||||
property.usage &= ~PROPERTY_USAGE_EDITOR;
|
||||
|
||||
func _ready() -> void:
|
||||
_core = DynamicSoundFXPlayerCore.new(self);
|
||||
_core.ready();
|
||||
|
||||
@@ -3,8 +3,9 @@ class_name DynamicSoundFXPlayerCore
|
||||
##
|
||||
## Owned by [DynamicSoundFXPlayer], [DynamicSoundFXPlayer2D], and [DynamicSoundFXPlayer3D].
|
||||
## Operates on its owner via duck-typed property access — the owner must expose
|
||||
## [code]Sound[/code], [code]Intensity[/code], [code]volume_db[/code], [code]play()[/code],
|
||||
## and [code]get_stream_playback()[/code].
|
||||
## [code]Sound[/code], [code]Intensity[/code], [code]PitchMode[/code],
|
||||
## [code]RandomMinPitchScale[/code], [code]RandomMaxPitchScale[/code],
|
||||
## [code]volume_db[/code], [code]play()[/code], and [code]get_stream_playback()[/code].
|
||||
extends RefCounted
|
||||
|
||||
var _player;
|
||||
@@ -23,14 +24,20 @@ func play_fx() -> void:
|
||||
var sound : DynamicSound = _player.Sound;
|
||||
if sound == null or _playback == null:
|
||||
return;
|
||||
var pitch : float = _resolve_pitch();
|
||||
var layers : Array[AudioStream] = [];
|
||||
if sound.Intensity1 != null: layers.append(sound.Intensity1);
|
||||
if sound.Intensity2 != null: layers.append(sound.Intensity2);
|
||||
if sound.Intensity3 != null: layers.append(sound.Intensity3);
|
||||
var real_intensity : float = _player.Intensity if layers.size() == 3 else 0.0;
|
||||
for i in layers.size():
|
||||
var id : int = _playback.play_stream(layers[i]);
|
||||
var id : int = _playback.play_stream(layers[i], 0.0, 0.0, pitch);
|
||||
if id == AudioStreamPlaybackPolyphonic.INVALID_ID:
|
||||
continue;
|
||||
var vol_lin : float = max((.5 - abs(float(i) / 2 - real_intensity)) / .5, 0.0);
|
||||
_playback.set_stream_volume(id, linear_to_db(db_to_linear(_player.volume_db) * vol_lin));
|
||||
|
||||
func _resolve_pitch() -> float:
|
||||
if _player.PitchMode == DynamicSoundConstants.PitchMode.Random:
|
||||
return 1.0 + randf_range(_player.RandomMinPitchScale, _player.RandomMaxPitchScale);
|
||||
return 1.0;
|
||||
|
||||
@@ -22,17 +22,6 @@ extends AudioStreamPlayer
|
||||
## When true, finished songs are re-appended to the back of the queue so the playlist cycles forever.
|
||||
@export var Loop : bool;
|
||||
|
||||
## How playback pitch is selected.
|
||||
@export var PitchMode : DynamicSoundConstants.PitchMode = DynamicSoundConstants.PitchMode.Constant:
|
||||
set(value):
|
||||
PitchMode = value;
|
||||
notify_property_list_changed();
|
||||
|
||||
## Minimum pitch scale when [member PitchMode] is Random.
|
||||
@export var RandomMinPitchScale : float = -0.5;
|
||||
## Maximum pitch scale when [member PitchMode] is Random.
|
||||
@export var RandomMaxPitchScale : float = 0.5;
|
||||
|
||||
var _core : DynamicSoundPlayerCore;
|
||||
|
||||
func _set(property: StringName, value: Variant) -> bool:
|
||||
@@ -49,11 +38,6 @@ func _enter_tree() -> void:
|
||||
if bus == &"Master" and AudioServer.get_bus_index("Music") != -1:
|
||||
bus = "Music";
|
||||
|
||||
func _validate_property(property: Dictionary) -> void:
|
||||
if property.name in ["RandomMinPitchScale", "RandomMaxPitchScale"]:
|
||||
if PitchMode != DynamicSoundConstants.PitchMode.Random:
|
||||
property.usage &= ~PROPERTY_USAGE_EDITOR;
|
||||
|
||||
func _ready() -> void:
|
||||
_core = DynamicSoundPlayerCore.new(self);
|
||||
_core.ready();
|
||||
|
||||
@@ -21,17 +21,6 @@ extends AudioStreamPlayer2D
|
||||
## When true, finished songs are re-appended to the back of the queue so the playlist cycles forever.
|
||||
@export var Loop : bool;
|
||||
|
||||
## How playback pitch is selected.
|
||||
@export var PitchMode : DynamicSoundConstants.PitchMode = DynamicSoundConstants.PitchMode.Constant:
|
||||
set(value):
|
||||
PitchMode = value;
|
||||
notify_property_list_changed();
|
||||
|
||||
## Minimum pitch scale when [member PitchMode] is Random.
|
||||
@export var RandomMinPitchScale : float = -0.5;
|
||||
## Maximum pitch scale when [member PitchMode] is Random.
|
||||
@export var RandomMaxPitchScale : float = 0.5;
|
||||
|
||||
var _core : DynamicSoundPlayerCore;
|
||||
|
||||
func _set(property: StringName, value: Variant) -> bool:
|
||||
@@ -48,11 +37,6 @@ func _enter_tree() -> void:
|
||||
if bus == &"Master" and AudioServer.get_bus_index("Music") != -1:
|
||||
bus = "Music";
|
||||
|
||||
func _validate_property(property: Dictionary) -> void:
|
||||
if property.name in ["RandomMinPitchScale", "RandomMaxPitchScale"]:
|
||||
if PitchMode != DynamicSoundConstants.PitchMode.Random:
|
||||
property.usage &= ~PROPERTY_USAGE_EDITOR;
|
||||
|
||||
func _ready() -> void:
|
||||
_core = DynamicSoundPlayerCore.new(self);
|
||||
_core.ready();
|
||||
|
||||
@@ -21,17 +21,6 @@ extends AudioStreamPlayer3D
|
||||
## When true, finished songs are re-appended to the back of the queue so the playlist cycles forever.
|
||||
@export var Loop : bool;
|
||||
|
||||
## How playback pitch is selected.
|
||||
@export var PitchMode : DynamicSoundConstants.PitchMode = DynamicSoundConstants.PitchMode.Constant:
|
||||
set(value):
|
||||
PitchMode = value;
|
||||
notify_property_list_changed();
|
||||
|
||||
## Minimum pitch scale when [member PitchMode] is Random.
|
||||
@export var RandomMinPitchScale : float = -0.5;
|
||||
## Maximum pitch scale when [member PitchMode] is Random.
|
||||
@export var RandomMaxPitchScale : float = 0.5;
|
||||
|
||||
var _core : DynamicSoundPlayerCore;
|
||||
|
||||
func _set(property: StringName, value: Variant) -> bool:
|
||||
@@ -48,11 +37,6 @@ func _enter_tree() -> void:
|
||||
if bus == &"Master" and AudioServer.get_bus_index("Music") != -1:
|
||||
bus = "Music";
|
||||
|
||||
func _validate_property(property: Dictionary) -> void:
|
||||
if property.name in ["RandomMinPitchScale", "RandomMaxPitchScale"]:
|
||||
if PitchMode != DynamicSoundConstants.PitchMode.Random:
|
||||
property.usage &= ~PROPERTY_USAGE_EDITOR;
|
||||
|
||||
func _ready() -> void:
|
||||
_core = DynamicSoundPlayerCore.new(self);
|
||||
_core.ready();
|
||||
|
||||
Reference in New Issue
Block a user