Initial commit
This commit is contained in:
commit
7becdd23b6
989 changed files with 28526 additions and 0 deletions
|
|
@ -0,0 +1,38 @@
|
|||
class_name NullPooledAudioStreamPlayer
|
||||
extends PooledAudioStreamPlayer
|
||||
## An extension of PooledAudioStreamPlayer that nerfs all of its public methods.
|
||||
|
||||
|
||||
## Whether this player is a [PooledAudioStreamPlayer], or a Null instance.
|
||||
func is_null() -> bool:
|
||||
return true
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer.trigger]
|
||||
func trigger() -> void:
|
||||
return
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer.trigger_varied]
|
||||
func trigger_varied(p_pitch: float = 1.0, p_volume: float = 0.0) -> void:
|
||||
return
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer.reset_volume]
|
||||
func reset_volume() -> void:
|
||||
return
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer.reset_pitch]
|
||||
func reset_pitch() -> void:
|
||||
return
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer.reset_all]
|
||||
func reset_all() -> void:
|
||||
return
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer.release]
|
||||
func release(p_finish_playing: bool = false) -> void:
|
||||
return
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
class_name NullPooledAudioStreamPlayer2D
|
||||
extends PooledAudioStreamPlayer2D
|
||||
## An extension of PooledAudioStreamPlayer2D that nerfs all of its public methods.
|
||||
|
||||
|
||||
## Whether this player is a [PooledAudioStreamPlayer2D], or a Null instance.
|
||||
func is_null() -> bool:
|
||||
return true
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer2D.trigger]
|
||||
func trigger() -> void:
|
||||
return
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer2D.trigger_varied]
|
||||
func trigger_varied(p_pitch: float = 1.0, p_volume: float = 0.0) -> void:
|
||||
return
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer2D.reset_volume]
|
||||
func reset_volume() -> void:
|
||||
return
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer2D.reset_pitch]
|
||||
func reset_pitch() -> void:
|
||||
return
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer2D.reset_all]
|
||||
func reset_all() -> void:
|
||||
return
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer2D.release]
|
||||
func release(p_finish_playing: bool = false) -> void:
|
||||
return
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
class_name NullPooledAudioStreamPlayer3D
|
||||
extends PooledAudioStreamPlayer3D
|
||||
## An extension of PooledAudioStreamPlayer3D that nerfs all of its public methods.
|
||||
|
||||
|
||||
## Whether this player is a [PooledAudioStreamPlayer3D], or a Null instance.
|
||||
func is_null() -> bool:
|
||||
return true
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer3D.trigger]
|
||||
func trigger() -> void:
|
||||
return
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer3D.trigger_varied]
|
||||
func trigger_varied(p_pitch: float = 1.0, p_volume: float = 0.0) -> void:
|
||||
return
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer3D.reset_volume]
|
||||
func reset_volume() -> void:
|
||||
return
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer3D.reset_pitch]
|
||||
func reset_pitch() -> void:
|
||||
return
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer3D.reset_all]
|
||||
func reset_all() -> void:
|
||||
return
|
||||
|
||||
|
||||
## A nerfed (does nothing) version of [method PooledAudioStreamPlayer3D.release]
|
||||
func release(p_finish_playing: bool = false) -> void:
|
||||
return
|
||||
158
addons/resonate/sound_manager/pool_entity.gd
Normal file
158
addons/resonate/sound_manager/pool_entity.gd
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
class_name PoolEntity
|
||||
extends RefCounted
|
||||
## An abstract/static class to house all of the common PooledAudioStreamPlayer* functionality.
|
||||
|
||||
|
||||
const ResonateSettings = preload("../shared/resonate_settings.gd")
|
||||
|
||||
enum FollowType {DISABLED, IDLE, PHYSICS}
|
||||
|
||||
|
||||
## Create a new PooledAudioStreamPlayer*.
|
||||
static func create(p_base) -> Variant:
|
||||
p_base.process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
|
||||
return p_base
|
||||
|
||||
|
||||
## Configure a PooledAudioStreamPlayer*.
|
||||
static func configure(p_base, p_streams: Array, p_reserved: bool, p_bus: String, p_poly: bool, p_volume: float, p_pitch: float, p_mode: Node.ProcessMode) -> bool:
|
||||
p_base.streams = p_streams
|
||||
p_base.poly = p_poly
|
||||
p_base.bus = p_bus
|
||||
p_base.process_mode = p_mode
|
||||
p_base.reserved = p_reserved
|
||||
p_base.releasing = false
|
||||
p_base.volume_db = p_volume if not p_poly else 0.0
|
||||
p_base.pitch_scale = p_pitch if not p_poly else 1.0
|
||||
p_base.base_volume = p_volume
|
||||
p_base.base_pitch = p_pitch
|
||||
p_base.follow_target = null
|
||||
p_base.follow_type = FollowType.DISABLED
|
||||
|
||||
if not p_base.poly:
|
||||
return false
|
||||
|
||||
var _settings = ResonateSettings.new()
|
||||
|
||||
var max_polyphony = ProjectSettings.get_setting(
|
||||
_settings.MAX_POLYPHONY_SETTING_NAME,
|
||||
_settings.MAX_POLYPHONY_SETTING_DEFAULT)
|
||||
|
||||
p_base.stream = AudioStreamPolyphonic.new()
|
||||
p_base.max_polyphony = max_polyphony
|
||||
p_base.stream.polyphony = max_polyphony
|
||||
|
||||
return true
|
||||
|
||||
|
||||
## Attach a PooledAudioStreamPlayer* to a position or node.
|
||||
static func attach_to(p_base, p_node: Variant) -> void:
|
||||
if p_node == null:
|
||||
return
|
||||
|
||||
if ResonateUtils.is_vector(p_node):
|
||||
p_base.global_position = p_node
|
||||
|
||||
if ResonateUtils.is_node(p_node):
|
||||
p_base.follow_target = p_node
|
||||
p_base.follow_type = FollowType.IDLE
|
||||
|
||||
|
||||
## Sync a PooledAudioStreamPlayer*'s transform with its target's when applicable.
|
||||
static func sync_process(p_base) -> void:
|
||||
if p_base.follow_target == null:
|
||||
return
|
||||
|
||||
if not is_instance_valid(p_base.follow_target):
|
||||
return
|
||||
|
||||
if p_base.follow_type != FollowType.IDLE:
|
||||
return
|
||||
|
||||
p_base.global_position = p_base.follow_target.global_position
|
||||
|
||||
|
||||
## Sync a PooledAudioStreamPlayer*'s transform with its target's
|
||||
## when applicable during the physics step.
|
||||
static func sync_physics_process(p_base) -> void:
|
||||
if p_base.follow_target == null:
|
||||
return
|
||||
|
||||
if not is_instance_valid(p_base.follow_target):
|
||||
return
|
||||
|
||||
if p_base.follow_type != FollowType.PHYSICS:
|
||||
return
|
||||
|
||||
p_base.global_position = p_base.follow_target.global_position
|
||||
|
||||
|
||||
## Trigger a PooledAudioStreamPlayer*.
|
||||
static func trigger(p_base, p_varied: bool, p_pitch: float, p_volume: float) -> bool:
|
||||
if p_base.streams.size() == 0:
|
||||
push_warning("Resonate - The player [%s] does not contain any streams, ensure you're using the SoundManager to instance it correctly." % p_base.name)
|
||||
return false
|
||||
|
||||
var next_stream = p_base.streams.pick_random()
|
||||
|
||||
if not p_base.poly and p_varied:
|
||||
p_base.volume_db = p_volume
|
||||
p_base.pitch_scale = p_pitch
|
||||
|
||||
if not p_base.poly:
|
||||
p_base.stream = next_stream
|
||||
return true
|
||||
|
||||
var playback = p_base.get_stream_playback() as AudioStreamPlaybackPolyphonic
|
||||
|
||||
if p_varied:
|
||||
playback.play_stream(next_stream, 0, p_volume, p_pitch)
|
||||
else:
|
||||
playback.play_stream(next_stream, 0, p_base.base_volume, p_base.base_pitch)
|
||||
|
||||
return false
|
||||
|
||||
|
||||
## Reset the volume of a PooledAudioStreamPlayer*.
|
||||
static func reset_volume(p_base) -> void:
|
||||
p_base.volume_db = p_base.base_volume
|
||||
|
||||
|
||||
## Reset the pitch of a PooledAudioStreamPlayer*.
|
||||
static func reset_pitch(p_base) -> void:
|
||||
p_base.pitch_scale = p_base.base_pitch
|
||||
|
||||
|
||||
## Reset both the volume and pitch of a PooledAudioStreamPlayer*.
|
||||
static func reset_all(p_base) -> void:
|
||||
p_base.volume_db = p_base.base_volume
|
||||
p_base.pitch_scale = p_base.base_pitch
|
||||
|
||||
|
||||
## Release a PooledAudioStreamPlayer* back into the pool.
|
||||
static func release(p_base, p_finish_playing: bool) -> void:
|
||||
if p_base.releasing:
|
||||
return
|
||||
|
||||
var has_loops = p_base.streams.any(ResonateUtils.is_stream_looped)
|
||||
|
||||
if p_finish_playing and has_loops:
|
||||
push_warning("Resonate - The player [%s] has looping streams and therefore will never release itself back to the pool (as playback continues indefinitely). It will be forced to stop." % p_base.name)
|
||||
p_base.stop()
|
||||
|
||||
if not p_finish_playing:
|
||||
p_base.stop()
|
||||
|
||||
p_base.reserved = false
|
||||
p_base.process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
p_base.releasing = true
|
||||
p_base.released.emit()
|
||||
|
||||
|
||||
## A callback to release a PooledAudioStreamPlayer* when it finishes playing.
|
||||
static func finished(p_base) -> void:
|
||||
if p_base.reserved:
|
||||
return
|
||||
|
||||
p_base.release()
|
||||
124
addons/resonate/sound_manager/pooled_audio_stream_player.gd
Normal file
124
addons/resonate/sound_manager/pooled_audio_stream_player.gd
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
class_name PooledAudioStreamPlayer
|
||||
extends AudioStreamPlayer
|
||||
## An extension of AudioStreamPlayer that manages sequential and
|
||||
## polyphonic playback as part of a pool of players.
|
||||
|
||||
|
||||
## Emitted when this player has been released and should return to the pool.
|
||||
signal released
|
||||
|
||||
## Whether this player has been reserved.
|
||||
var reserved: bool
|
||||
|
||||
## Whether this player is in the process of being released.
|
||||
var releasing: bool
|
||||
|
||||
## Whether this player has been configured to support polyphonic playback.
|
||||
var poly: bool
|
||||
|
||||
## The collection of streams configured on this player.
|
||||
var streams: Array
|
||||
|
||||
## The base/fallback volume of this player.
|
||||
var base_volume: float
|
||||
|
||||
## The base/fallback pitch of this player.
|
||||
var base_pitch: float
|
||||
|
||||
## The target this player should follow in 2D or 3D space.
|
||||
var follow_target: Node
|
||||
|
||||
## When the player should sync its transform when following a target.
|
||||
var follow_type: PoolEntity.FollowType
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Lifecycle methods
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
finished.connect(_on_finished)
|
||||
|
||||
|
||||
func _process(_p_delta) -> void:
|
||||
PoolEntity.sync_process(self)
|
||||
|
||||
|
||||
func _physics_process(_p_delta) -> void:
|
||||
PoolEntity.sync_physics_process(self)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public methods
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## Returns a new player.
|
||||
static func create() -> PooledAudioStreamPlayer:
|
||||
return PoolEntity.create(PooledAudioStreamPlayer.new())
|
||||
|
||||
|
||||
## Whether this player is a [NullPooledAudioStreamPlayer], or real instance.
|
||||
func is_null() -> bool:
|
||||
return false
|
||||
|
||||
|
||||
## Configure this player with the given streams and charateristics.
|
||||
func configure(p_streams: Array, p_reserved: bool, p_bus: String, p_poly: bool, p_volume: float, p_pitch: float, p_mode: Node.ProcessMode) -> void:
|
||||
var is_polyphonic = PoolEntity.configure(self, p_streams, p_reserved, p_bus, p_poly, p_volume, p_pitch, p_mode)
|
||||
|
||||
if is_polyphonic:
|
||||
super.play()
|
||||
|
||||
|
||||
## Attach this player to a 2D/3D position or node.
|
||||
func attach_to(p_node: Variant) -> void:
|
||||
PoolEntity.attach_to(self, p_node)
|
||||
|
||||
|
||||
## Trigger (play) a random variation associated with this player.
|
||||
func trigger() -> void:
|
||||
var should_play = PoolEntity.trigger(self, false, 1.0, 0.0)
|
||||
|
||||
if should_play:
|
||||
super.play()
|
||||
|
||||
|
||||
## Trigger (play) a random variation associated with this
|
||||
## player with the given volume and pitch settings.
|
||||
func trigger_varied(p_pitch: float = 1.0, p_volume: float = 0.0) -> void:
|
||||
var should_play = PoolEntity.trigger(self, true, p_pitch, p_volume)
|
||||
|
||||
if should_play:
|
||||
super.play()
|
||||
|
||||
|
||||
## Reset the volume of this player back to the default set in its bank.
|
||||
func reset_volume() -> void:
|
||||
PoolEntity.reset_volume(self)
|
||||
|
||||
|
||||
## Reset the pitch of this player back to the default set in its bank.
|
||||
func reset_pitch() -> void:
|
||||
PoolEntity.reset_pitch(self)
|
||||
|
||||
|
||||
## Reset both the volume and pitch of this player back to the default set in its bank.
|
||||
func reset_all() -> void:
|
||||
PoolEntity.reset_all(self)
|
||||
|
||||
|
||||
## Release this player back to the pool, and optionally
|
||||
## wait for it to finish playing before doing so.
|
||||
func release(p_finish_playing: bool = false) -> void:
|
||||
PoolEntity.release(self, p_finish_playing)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private methods
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _on_finished() -> void:
|
||||
PoolEntity.finished(self)
|
||||
124
addons/resonate/sound_manager/pooled_audio_stream_player_2d.gd
Normal file
124
addons/resonate/sound_manager/pooled_audio_stream_player_2d.gd
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
class_name PooledAudioStreamPlayer2D
|
||||
extends AudioStreamPlayer2D
|
||||
## An extension of AudioStreamPlayer2D that manages sequential and
|
||||
## polyphonic playback as part of a pool of players.
|
||||
|
||||
|
||||
## Emitted when this player has been released and should return to the pool.
|
||||
signal released
|
||||
|
||||
## Whether this player has been reserved.
|
||||
var reserved: bool
|
||||
|
||||
## Whether this player is in the process of being released.
|
||||
var releasing: bool
|
||||
|
||||
## Whether this player has been configured to support polyphonic playback.
|
||||
var poly: bool
|
||||
|
||||
## The collection of streams configured on this player.
|
||||
var streams: Array
|
||||
|
||||
## The base/fallback volume of this player.
|
||||
var base_volume: float
|
||||
|
||||
## The base/fallback pitch of this player.
|
||||
var base_pitch: float
|
||||
|
||||
## The target this player should follow in 2D or 3D space.
|
||||
var follow_target: Node
|
||||
|
||||
## When the player should sync its transform when following a target.
|
||||
var follow_type: PoolEntity.FollowType
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Lifecycle methods
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
finished.connect(_on_finished)
|
||||
|
||||
|
||||
func _process(_p_delta) -> void:
|
||||
PoolEntity.sync_process(self)
|
||||
|
||||
|
||||
func _physics_process(_p_delta) -> void:
|
||||
PoolEntity.sync_physics_process(self)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public methods
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## Returns a new player.
|
||||
static func create() -> PooledAudioStreamPlayer2D:
|
||||
return PoolEntity.create(PooledAudioStreamPlayer2D.new())
|
||||
|
||||
|
||||
## Whether this player is a [NullPooledAudioStreamPlayer2D], or real instance.
|
||||
func is_null() -> bool:
|
||||
return false
|
||||
|
||||
|
||||
## Configure this player with the given streams and charateristics.
|
||||
func configure(p_streams: Array, p_reserved: bool, p_bus: String, p_poly: bool, p_volume: float, p_pitch: float, p_mode: Node.ProcessMode) -> void:
|
||||
var is_polyphonic = PoolEntity.configure(self, p_streams, p_reserved, p_bus, p_poly, p_volume, p_pitch, p_mode)
|
||||
|
||||
if is_polyphonic:
|
||||
super.play()
|
||||
|
||||
|
||||
## Attach this player to a 2D/3D position or node.
|
||||
func attach_to(p_node: Variant) -> void:
|
||||
PoolEntity.attach_to(self, p_node)
|
||||
|
||||
|
||||
## Trigger (play) a random variation associated with this player.
|
||||
func trigger() -> void:
|
||||
var should_play = PoolEntity.trigger(self, false, 1.0, 0.0)
|
||||
|
||||
if should_play:
|
||||
super.play()
|
||||
|
||||
|
||||
## Trigger (play) a random variation associated with this
|
||||
## player with the given volume and pitch settings.
|
||||
func trigger_varied(p_pitch: float = 1.0, p_volume: float = 0.0) -> void:
|
||||
var should_play = PoolEntity.trigger(self, true, p_pitch, p_volume)
|
||||
|
||||
if should_play:
|
||||
super.play()
|
||||
|
||||
|
||||
## Reset the volume of this player back to the default set in its bank.
|
||||
func reset_volume() -> void:
|
||||
PoolEntity.reset_volume(self)
|
||||
|
||||
|
||||
## Reset the pitch of this player back to the default set in its bank.
|
||||
func reset_pitch() -> void:
|
||||
PoolEntity.reset_pitch(self)
|
||||
|
||||
|
||||
## Reset both the volume and pitch of this player back to the default set in its bank.
|
||||
func reset_all() -> void:
|
||||
PoolEntity.reset_all(self)
|
||||
|
||||
|
||||
## Release this player back to the pool, and optionally
|
||||
## wait for it to finish playing before doing so.
|
||||
func release(p_finish_playing: bool = false) -> void:
|
||||
PoolEntity.release(self, p_finish_playing)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private methods
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _on_finished() -> void:
|
||||
PoolEntity.finished(self)
|
||||
124
addons/resonate/sound_manager/pooled_audio_stream_player_3d.gd
Normal file
124
addons/resonate/sound_manager/pooled_audio_stream_player_3d.gd
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
class_name PooledAudioStreamPlayer3D
|
||||
extends AudioStreamPlayer3D
|
||||
## An extension of AudioStreamPlayer3D that manages sequential and
|
||||
## polyphonic playback as part of a pool of players.
|
||||
|
||||
|
||||
## Emitted when this player has been released and should return to the pool.
|
||||
signal released
|
||||
|
||||
## Whether this player has been reserved.
|
||||
var reserved: bool
|
||||
|
||||
## Whether this player is in the process of being released.
|
||||
var releasing: bool
|
||||
|
||||
## Whether this player has been configured to support polyphonic playback.
|
||||
var poly: bool
|
||||
|
||||
## The collection of streams configured on this player.
|
||||
var streams: Array
|
||||
|
||||
## The base/fallback volume of this player.
|
||||
var base_volume: float
|
||||
|
||||
## The base/fallback pitch of this player.
|
||||
var base_pitch: float
|
||||
|
||||
## The target this player should follow in 2D or 3D space.
|
||||
var follow_target: Node
|
||||
|
||||
## When the player should sync its transform when following a target.
|
||||
var follow_type: PoolEntity.FollowType
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Lifecycle methods
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
finished.connect(_on_finished)
|
||||
|
||||
|
||||
func _process(_p_delta) -> void:
|
||||
PoolEntity.sync_process(self)
|
||||
|
||||
|
||||
func _physics_process(_p_delta) -> void:
|
||||
PoolEntity.sync_physics_process(self)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public methods
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## Returns a new player.
|
||||
static func create() -> PooledAudioStreamPlayer3D:
|
||||
return PoolEntity.create(PooledAudioStreamPlayer3D.new())
|
||||
|
||||
|
||||
## Whether this player is a [NullPooledAudioStreamPlayer3D], or real instance.
|
||||
func is_null() -> bool:
|
||||
return false
|
||||
|
||||
|
||||
## Configure this player with the given streams and charateristics.
|
||||
func configure(p_streams: Array, p_reserved: bool, p_bus: String, p_poly: bool, p_volume: float, p_pitch: float, p_mode: Node.ProcessMode) -> void:
|
||||
var is_polyphonic = PoolEntity.configure(self, p_streams, p_reserved, p_bus, p_poly, p_volume, p_pitch, p_mode)
|
||||
|
||||
if is_polyphonic:
|
||||
super.play()
|
||||
|
||||
|
||||
## Attach this player to a 2D/3D position or node.
|
||||
func attach_to(p_node: Variant) -> void:
|
||||
PoolEntity.attach_to(self, p_node)
|
||||
|
||||
|
||||
## Trigger (play) a random variation associated with this player.
|
||||
func trigger() -> void:
|
||||
var should_play = PoolEntity.trigger(self, false, 1.0, 0.0)
|
||||
|
||||
if should_play:
|
||||
super.play()
|
||||
|
||||
|
||||
## Trigger (play) a random variation associated with this
|
||||
## player with the given volume and pitch settings.
|
||||
func trigger_varied(p_pitch: float = 1.0, p_volume: float = 0.0) -> void:
|
||||
var should_play = PoolEntity.trigger(self, true, p_pitch, p_volume)
|
||||
|
||||
if should_play:
|
||||
super.play()
|
||||
|
||||
|
||||
## Reset the volume of this player back to the default set in its bank.
|
||||
func reset_volume() -> void:
|
||||
PoolEntity.reset_volume(self)
|
||||
|
||||
|
||||
## Reset the pitch of this player back to the default set in its bank.
|
||||
func reset_pitch() -> void:
|
||||
PoolEntity.reset_pitch(self)
|
||||
|
||||
|
||||
## Reset both the volume and pitch of this player back to the default set in its bank.
|
||||
func reset_all() -> void:
|
||||
PoolEntity.reset_all(self)
|
||||
|
||||
|
||||
## Release this player back to the pool, and optionally
|
||||
## wait for it to finish playing before doing so.
|
||||
func release(p_finish_playing: bool = false) -> void:
|
||||
PoolEntity.release(self, p_finish_playing)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private methods
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _on_finished() -> void:
|
||||
PoolEntity.finished(self)
|
||||
17
addons/resonate/sound_manager/sound_bank.gd
Normal file
17
addons/resonate/sound_manager/sound_bank.gd
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
class_name SoundBank
|
||||
extends Node
|
||||
## A container used to store & group sound events in your scene.
|
||||
|
||||
|
||||
## This bank's unique identifier.
|
||||
@export var label: String
|
||||
|
||||
## The bus to use for all sound events in this bank.[br][br]
|
||||
## [b]Note:[/b] this will override the bus set in your project settings (Audio/Manager/Sound/Bank)
|
||||
@export var bus: String
|
||||
|
||||
## The underlying process mode for all sound events in this bank.
|
||||
@export var mode: Node.ProcessMode
|
||||
|
||||
## The collection of sound events associated with this bank.
|
||||
@export var events: Array[SoundEventResource]
|
||||
15
addons/resonate/sound_manager/sound_bank.svg
Normal file
15
addons/resonate/sound_manager/sound_bank.svg
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 16 16">
|
||||
<g clip-path="url(#a)">
|
||||
<path fill="url(#b)" d="M14 0H2a2 2 0 0 0-2 2v12c0 1.1.9 2 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2ZM4.47 11.18a1.19 1.19 0 0 1-1.62.46 1.19 1.19 0 0 1-.47-1.62c.36-.65.55-1.33.55-2.02a4.1 4.1 0 0 0-.55-2.03 1.2 1.2 0 0 1 .47-1.62 1.2 1.2 0 0 1 1.62.46 6.4 6.4 0 0 1 0 6.36v.01Zm3.88 1.37a1.2 1.2 0 0 1-1.62.46 1.2 1.2 0 0 1-.45-1.62 6.91 6.91 0 0 0 0-6.76 1.2 1.2 0 0 1 .45-1.62 1.2 1.2 0 0 1 1.62.46 9.3 9.3 0 0 1 0 9.1v-.02Zm3.85 1.35a1.2 1.2 0 0 1-1.63.45 1.16 1.16 0 0 1-.56-.72c-.08-.31-.05-.63.11-.9a9.58 9.58 0 0 0 0-9.46c-.16-.28-.2-.6-.11-.9.08-.31.28-.56.56-.72a1.2 1.2 0 0 1 1.62.45 12 12 0 0 1 0 11.8h.01Z"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="b" x1="2.9" x2="13.1" y1="16.83" y2="-.83" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#9F9"/>
|
||||
<stop offset=".5" stop-color="#E6D767"/>
|
||||
<stop offset="1" stop-color="#EA6C5E"/>
|
||||
</linearGradient>
|
||||
<clipPath id="a">
|
||||
<path fill="#fff" d="M0 0h16v16H0z"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
37
addons/resonate/sound_manager/sound_bank.svg.import
Normal file
37
addons/resonate/sound_manager/sound_bank.svg.import
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ntgipyp6jv34"
|
||||
path="res://.godot/imported/sound_bank.svg-d1b3f43714c54a9c122e6a364a95c7d8.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/resonate/sound_manager/sound_bank.svg"
|
||||
dest_files=["res://.godot/imported/sound_bank.svg-d1b3f43714c54a9c122e6a364a95c7d8.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
21
addons/resonate/sound_manager/sound_event_resource.gd
Normal file
21
addons/resonate/sound_manager/sound_event_resource.gd
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
class_name SoundEventResource
|
||||
extends Resource
|
||||
## The container used to store the details of a sound event.
|
||||
|
||||
|
||||
## This sound event's unique identifier.
|
||||
@export var name: String = ""
|
||||
|
||||
## The bus to use for all sound events in this bank.[br][br]
|
||||
## [b]Note:[/b] this will override the bus set in this events sound bank,
|
||||
## or your project settings (Audio/Manager/Sound/Bank)
|
||||
@export var bus: String = ""
|
||||
|
||||
## The volume of the sound event.
|
||||
@export_range(-80.0, 6.0, 0.1, "suffix:dB") var volume: float = 0.0
|
||||
|
||||
## The pitch of the sound event.
|
||||
@export var pitch: float = 1.0
|
||||
|
||||
## The collection of audio streams (variations) associated with this sound event.
|
||||
@export var streams: Array[AudioStream]
|
||||
493
addons/resonate/sound_manager/sound_manager.gd
Normal file
493
addons/resonate/sound_manager/sound_manager.gd
Normal file
|
|
@ -0,0 +1,493 @@
|
|||
extends Node
|
||||
## The SoundManager is responsible for all sound events in your game.
|
||||
##
|
||||
## It manages pools of 1D, 2D, and 3D audio stream players, which can be used
|
||||
## for single-shot sound events, or reserved by scripts for repetitive & exclusive use.
|
||||
## Sound events can contain many variations which will be chosen and played at random.
|
||||
## Playback can be achieved both sequentially and polyphonically.
|
||||
##
|
||||
## @tutorial(View example scenes): https://github.com/hugemenace/resonate/tree/main/examples
|
||||
|
||||
|
||||
const ResonateSettings = preload("../shared/resonate_settings.gd")
|
||||
var _settings = ResonateSettings.new()
|
||||
|
||||
## Emitted only once when the SoundManager has finished setting up and
|
||||
## is ready to play or instance sound events.
|
||||
signal loaded
|
||||
|
||||
## Emitted every time the SoundManager detects that a SoundBank has
|
||||
## been added or removed from the scene tree.
|
||||
signal banks_updated
|
||||
|
||||
## Emitted every time one of the player pools is updated.
|
||||
signal pools_updated
|
||||
|
||||
## Emitted whenever [signal SoundManager.loaded], [signal SoundManager.banks_updated],
|
||||
## or [signal SoundManager.pools_updated] is emitted.
|
||||
signal updated
|
||||
|
||||
## Whether the SoundManager has completed setup and is ready to play or instance sound events.
|
||||
var has_loaded: bool = false
|
||||
|
||||
var _1d_players: Array[PooledAudioStreamPlayer] = []
|
||||
var _2d_players: Array[PooledAudioStreamPlayer2D] = []
|
||||
var _3d_players: Array[PooledAudioStreamPlayer3D] = []
|
||||
var _event_table: Dictionary = {}
|
||||
var _event_table_hash: int
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Lifecycle methods
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _init():
|
||||
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_initialise_pool(ProjectSettings.get_setting(
|
||||
_settings.POOL_1D_SIZE_SETTING_NAME,
|
||||
_settings.POOL_1D_SIZE_SETTING_DEFAULT),
|
||||
_create_player_1d)
|
||||
|
||||
_initialise_pool(ProjectSettings.get_setting(
|
||||
_settings.POOL_2D_SIZE_SETTING_NAME,
|
||||
_settings.POOL_2D_SIZE_SETTING_DEFAULT),
|
||||
_create_player_2d)
|
||||
|
||||
_initialise_pool(ProjectSettings.get_setting(
|
||||
_settings.POOL_3D_SIZE_SETTING_NAME,
|
||||
_settings.POOL_3D_SIZE_SETTING_DEFAULT),
|
||||
_create_player_3d)
|
||||
|
||||
_auto_add_events()
|
||||
|
||||
var scene_root = get_tree().root.get_tree()
|
||||
scene_root.node_added.connect(_on_scene_node_added)
|
||||
scene_root.node_removed.connect(_on_scene_node_removed)
|
||||
|
||||
|
||||
func _process(_p_delta) -> void:
|
||||
if _event_table_hash != _event_table.hash():
|
||||
_event_table_hash = _event_table.hash()
|
||||
banks_updated.emit()
|
||||
updated.emit()
|
||||
|
||||
if has_loaded:
|
||||
return
|
||||
|
||||
has_loaded = true
|
||||
loaded.emit()
|
||||
updated.emit()
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public methods
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
## Returns a new Null player (null object pattern) which mimics a [PooledAudioStreamPlayer],
|
||||
## allowing you to call methods such as [method PooledAudioStreamPlayer.trigger]
|
||||
## without the need to wrap the call in a null check.
|
||||
func null_instance() -> NullPooledAudioStreamPlayer:
|
||||
return NullPooledAudioStreamPlayer.new()
|
||||
|
||||
|
||||
## Returns a new Null player (null object pattern) which mimics a [PooledAudioStreamPlayer2D],
|
||||
## allowing you to call methods such as [method PooledAudioStreamPlayer2D.trigger]
|
||||
## without the need to wrap the call in a null check.
|
||||
func null_instance_2d() -> NullPooledAudioStreamPlayer2D:
|
||||
return NullPooledAudioStreamPlayer2D.new()
|
||||
|
||||
|
||||
## Returns a new Null player (null object pattern) which mimics a [PooledAudioStreamPlayer3D],
|
||||
## allowing you to call methods such as [method PooledAudioStreamPlayer3D.trigger]
|
||||
## without the need to wrap the call in a null check.
|
||||
func null_instance_3d() -> NullPooledAudioStreamPlayer3D:
|
||||
return NullPooledAudioStreamPlayer3D.new()
|
||||
|
||||
|
||||
## Used to determine whether the given [b]p_instance[/b] variable can be instantiated. It will return
|
||||
## true if the SoundManager hasn't loaded yet, if the instance is already instantiated,
|
||||
## or if the instance has been instantiated but is currently being released.
|
||||
func should_skip_instancing(p_instance) -> bool:
|
||||
if not has_loaded:
|
||||
return true
|
||||
|
||||
if p_instance != null and p_instance.releasing:
|
||||
return true
|
||||
|
||||
if p_instance != null and not p_instance.is_null():
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
|
||||
## This a shorthand method used to instantiate a new instance while optionally configuring it
|
||||
## to be automatically released when the given [b]p_base[/b] is removed from the scene tree.[br][br]
|
||||
## The [b]p_factory[/b] callable is used to create the instance required. See example below:[br][br]
|
||||
## [codeblock]
|
||||
## _instance_note_one = SoundManager.quick_instance(_instance_note_one,
|
||||
## SoundManager.instance.bind("example", "one"), self)
|
||||
## [/codeblock]
|
||||
func quick_instance(p_instance, p_factory: Callable, p_base: Node = null, p_finish_playing: bool = false) -> Variant:
|
||||
if should_skip_instancing(p_instance):
|
||||
return
|
||||
|
||||
var new_instance = p_factory.call()
|
||||
|
||||
if p_base != null:
|
||||
release_on_exit(p_base, new_instance, p_finish_playing)
|
||||
|
||||
return new_instance
|
||||
|
||||
|
||||
## Play a sound event from a SoundBank.
|
||||
func play(p_bank_label: String, p_event_name: String, p_bus: String = "") -> void:
|
||||
var instance = _instance_manual(p_bank_label, p_event_name, false, p_bus, false, null)
|
||||
instance.trigger()
|
||||
instance.release(true)
|
||||
|
||||
|
||||
## Play a sound event from a SoundBank at a specific [b]Vector2[/b] or [b]Vector3[/b] position.
|
||||
func play_at_position(p_bank_label: String, p_event_name: String, p_position, p_bus: String = "") -> void:
|
||||
var instance = _instance_manual(p_bank_label, p_event_name, false, p_bus, false, p_position)
|
||||
instance.trigger()
|
||||
instance.release(true)
|
||||
|
||||
|
||||
## Play a sound event from a SoundBank on a [b]Node2D[/b] or [b]Node3D[/b]. This causes the sound to
|
||||
## synchronise with the Node's global position - causing it to move in 2D or 3D space along with the Node.
|
||||
func play_on_node(p_bank_label: String, p_event_name: String, p_node, p_bus: String = "") -> void:
|
||||
var instance = _instance_manual(p_bank_label, p_event_name, false, p_bus, false, p_node)
|
||||
instance.trigger()
|
||||
instance.release(true)
|
||||
|
||||
|
||||
## Play a sound event from a SoundBank with the provided pitch and/or volume.
|
||||
func play_varied(p_bank_label: String, p_event_name: String, p_pitch: float = 1.0, p_volume: float = 0.0, p_bus: String = "") -> void:
|
||||
var instance = _instance_manual(p_bank_label, p_event_name, false, p_bus, false, null)
|
||||
instance.trigger_varied(p_pitch, p_volume)
|
||||
instance.release(true)
|
||||
|
||||
|
||||
## Play a sound event from a SoundBank at a specific [b]Vector2[/b] or [b]Vector3[/b]
|
||||
## position with the provided pitch and/or volume.
|
||||
func play_at_position_varied(p_bank_label: String, p_event_name: String, p_position, p_pitch: float = 1.0, p_volume: float = 0.0, p_bus: String = "") -> void:
|
||||
var instance = _instance_manual(p_bank_label, p_event_name, false, p_bus, false, p_position)
|
||||
instance.trigger_varied(p_pitch, p_volume)
|
||||
instance.release(true)
|
||||
|
||||
|
||||
## Play a sound event from a SoundBank on a [b]Node2D[/b] or [b]Node3D[/b] with the provided pitch
|
||||
## and/or volume. This causes the sound to synchronise with the Node's global position - causing
|
||||
## it to move in 2D or 3D space along with the Node.
|
||||
func play_on_node_varied(p_bank_label: String, p_event_name: String, p_node, p_pitch: float = 1.0, p_volume: float = 0.0, p_bus: String = "") -> void:
|
||||
var instance = _instance_manual(p_bank_label, p_event_name, false, p_bus, false, p_node)
|
||||
instance.trigger_varied(p_pitch, p_volume)
|
||||
instance.release(true)
|
||||
|
||||
|
||||
## Returns a reserved [PooledAudioStreamPlayer] for you to use exclusively until it is told to
|
||||
## [method PooledAudioStreamPlayer.release] or is automatically released when registered
|
||||
## with [method SoundManager.release_on_exit].
|
||||
func instance(p_bank_label: String, p_event_name: String, p_bus: String = "") -> Variant:
|
||||
return _instance_manual(p_bank_label, p_event_name, true, p_bus, false, null)
|
||||
|
||||
|
||||
## Returns a reserved [PooledAudioStreamPlayer2D] or [PooledAudioStreamPlayer3D] (depending on the
|
||||
## type of [b]p_position[/b]) placed at a specific 2D or 3D position in the world. You will have
|
||||
## exclusive use of it until it is told to [method PooledAudioStreamPlayer.release] or is automatically
|
||||
## released when registered with [method SoundManager.release_on_exit].
|
||||
func instance_at_position(p_bank_label: String, p_event_name: String, p_position, p_bus: String = "") -> Variant:
|
||||
return _instance_manual(p_bank_label, p_event_name, true, p_bus, false, p_position)
|
||||
|
||||
|
||||
## Returns a reserved [PooledAudioStreamPlayer2D] or [PooledAudioStreamPlayer3D] (depending on the
|
||||
## type of [b]p_node[/b]) which will synchronise its global position with [b]p_node[/b]. You will have
|
||||
## exclusive use of it until it is told to [method PooledAudioStreamPlayer.release] or is automatically
|
||||
## released when registered with [method SoundManager.release_on_exit].
|
||||
func instance_on_node(p_bank_label: String, p_event_name: String, p_node, p_bus: String = "") -> Variant:
|
||||
return _instance_manual(p_bank_label, p_event_name, true, p_bus, false, p_node)
|
||||
|
||||
|
||||
## Returns a reserved [PooledAudioStreamPlayer] for you to use exclusively until it is told to
|
||||
## [method PooledAudioStreamPlayer.release] or is automatically released when registered
|
||||
## with [method SoundManager.release_on_exit].[br][br]
|
||||
## [b]Note:[/b] This method will mark the reserved player as polyphonic (able to play
|
||||
## multiple event variations simultaneously.)
|
||||
func instance_poly(p_bank_label: String, p_event_name: String, p_bus: String = "") -> Variant:
|
||||
return _instance_manual(p_bank_label, p_event_name, true, p_bus, true, null)
|
||||
|
||||
|
||||
## Returns a reserved [PooledAudioStreamPlayer2D] or [PooledAudioStreamPlayer3D] (depending on the
|
||||
## type of [b]p_position[/b]) placed at a specific 2D or 3D position in the world. You will have
|
||||
## exclusive use of it until it is told to [method PooledAudioStreamPlayer.release] or is automatically
|
||||
## released when registered with [method SoundManager.release_on_exit].[br][br]
|
||||
## [b]Note:[/b] This method will mark the reserved player as polyphonic (able to play
|
||||
## multiple event variations simultaneously.)
|
||||
func instance_at_position_poly(p_bank_label: String, p_event_name: String, p_position, p_bus: String = "") -> Variant:
|
||||
return _instance_manual(p_bank_label, p_event_name, true, p_bus, true, p_position)
|
||||
|
||||
|
||||
## Returns a reserved [PooledAudioStreamPlayer2D] or [PooledAudioStreamPlayer3D] (depending on the
|
||||
## type of [b]p_node[/b]) which will synchronise its global position with [b]p_node[/b]. You will have
|
||||
## exclusive use of it until it is told to [method PooledAudioStreamPlayer.release] or is automatically
|
||||
## released when registered with [method SoundManager.release_on_exit].[br][br]
|
||||
## [b]Note:[/b] This method will mark the reserved player as polyphonic (able to play
|
||||
## multiple event variations simultaneously.)
|
||||
func instance_on_node_poly(p_bank_label: String, p_event_name: String, p_node, p_bus: String = "") -> Variant:
|
||||
return _instance_manual(p_bank_label, p_event_name, true, p_bus, true, p_node)
|
||||
|
||||
|
||||
## Will automatically release the given [b]p_instance[/b] when the provided
|
||||
## [b]p_base[/b] is removed from the scene tree.
|
||||
func release_on_exit(p_base: Node, p_instance: Node, p_finish_playing: bool = false) -> void:
|
||||
if p_instance == null or p_base == null:
|
||||
return
|
||||
|
||||
p_base.tree_exiting.connect(p_instance.release.bind(p_finish_playing))
|
||||
|
||||
|
||||
## Will automatically release the given [b]p_instance[/b] when the provided
|
||||
## [b]p_base[/b] is removed from the scene tree.[br][br]
|
||||
## [b]Note:[/b] This method has been deprecated, please use [method SoundManager.release_on_exit] instead.
|
||||
## @deprecated
|
||||
func auto_release(p_base: Node, p_instance: Node, p_finish_playing: bool = false) -> Variant:
|
||||
push_warning("Resonate - auto_release has been deprecated, please use release_on_exit instead.")
|
||||
|
||||
if p_instance == null:
|
||||
return p_instance
|
||||
|
||||
release_on_exit(p_base, p_instance, p_finish_playing)
|
||||
|
||||
return p_instance
|
||||
|
||||
|
||||
## Manually add a new SoundBank into the event cache.
|
||||
func add_bank(p_bank: SoundBank) -> void:
|
||||
_add_bank(p_bank)
|
||||
|
||||
|
||||
## Remove the provided bank from the event cache.
|
||||
func remove_bank(p_bank_label: String) -> void:
|
||||
if not _event_table.has(p_bank_label):
|
||||
return
|
||||
|
||||
_event_table.erase(p_bank_label)
|
||||
|
||||
|
||||
## Clear all banks from the event cache.
|
||||
func clear_banks() -> void:
|
||||
_event_table.clear()
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private methods
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _on_scene_node_added(p_node: Node) -> void:
|
||||
if not p_node is SoundBank:
|
||||
return
|
||||
|
||||
_add_bank(p_node)
|
||||
|
||||
|
||||
func _on_scene_node_removed(p_node: Node) -> void:
|
||||
if not p_node is SoundBank:
|
||||
return
|
||||
|
||||
_remove_bank(p_node)
|
||||
|
||||
|
||||
func _initialise_pool(p_size: int, p_creator_fn: Callable) -> void:
|
||||
for i in p_size:
|
||||
p_creator_fn.call_deferred()
|
||||
|
||||
|
||||
func _auto_add_events() -> void:
|
||||
var sound_banks = ResonateUtils.find_all_nodes(self, "SoundBank")
|
||||
|
||||
for sound_bank in sound_banks:
|
||||
_add_bank(sound_bank)
|
||||
|
||||
_event_table_hash = _event_table.hash()
|
||||
|
||||
|
||||
func _add_bank(p_bank: SoundBank) -> void:
|
||||
if _event_table.has(p_bank.label):
|
||||
_event_table[p_bank.label]["ref_count"] = \
|
||||
_event_table[p_bank.label]["ref_count"] + 1
|
||||
|
||||
return
|
||||
|
||||
_event_table[p_bank.label] = {
|
||||
"name": p_bank.label,
|
||||
"bus": p_bank.bus,
|
||||
"mode": p_bank.mode,
|
||||
"events": _create_events(p_bank.events),
|
||||
"ref_count": 1,
|
||||
}
|
||||
|
||||
|
||||
func _remove_bank(p_bank: SoundBank) -> void:
|
||||
if not _event_table.has(p_bank.label):
|
||||
return
|
||||
|
||||
if _event_table[p_bank.label]["ref_count"] == 1:
|
||||
_event_table.erase(p_bank.label)
|
||||
return
|
||||
|
||||
_event_table[p_bank.label]["ref_count"] = \
|
||||
_event_table[p_bank.label]["ref_count"] - 1
|
||||
|
||||
|
||||
func _create_events(p_events: Array[SoundEventResource]) -> Dictionary:
|
||||
var events = {}
|
||||
|
||||
for event in p_events:
|
||||
events[event.name] = {
|
||||
"name": event.name,
|
||||
"bus": event.bus,
|
||||
"volume": event.volume,
|
||||
"pitch": event.pitch,
|
||||
"streams": event.streams,
|
||||
}
|
||||
|
||||
return events
|
||||
|
||||
|
||||
func _get_bus(p_bank_bus: String, p_event_bus: String) -> String:
|
||||
if p_event_bus != null and p_event_bus != "":
|
||||
return p_event_bus
|
||||
|
||||
if p_bank_bus != null and p_bank_bus != "":
|
||||
return p_bank_bus
|
||||
|
||||
return ProjectSettings.get_setting(
|
||||
_settings.SOUND_BANK_BUS_SETTING_NAME,
|
||||
_settings.SOUND_BANK_BUS_SETTING_DEFAULT)
|
||||
|
||||
|
||||
func _instance_manual(p_bank_label: String, p_event_name: String, p_reserved: bool = false, p_bus: String = "", p_poly: bool = false, p_attachment = null) -> Variant:
|
||||
if not has_loaded:
|
||||
push_error("Resonate - The event [%s] on bank [%s] can't be instanced as the SoundManager has not loaded yet. Use the [loaded] signal/event to determine when it is ready." % [p_event_name, p_bank_label])
|
||||
return _get_null_player(p_attachment)
|
||||
|
||||
if not _event_table.has(p_bank_label):
|
||||
push_error("Resonate - Tried to instance the event [%s] from an unknown bank [%s]." % [p_event_name, p_bank_label])
|
||||
return _get_null_player(p_attachment)
|
||||
|
||||
if not _event_table[p_bank_label]["events"].has(p_event_name):
|
||||
push_error("Resonate - Tried to instance an unknown event [%s] from the bank [%s]." % [p_event_name, p_bank_label])
|
||||
return _get_null_player(p_attachment)
|
||||
|
||||
var bank = _event_table[p_bank_label] as Dictionary
|
||||
var event = bank["events"][p_event_name] as Dictionary
|
||||
|
||||
if event.streams.size() == 0:
|
||||
push_error("Resonate - The event [%s] on bank [%s] has no streams, you'll need to add one at minimum." % [p_event_name, p_bank_label])
|
||||
return _get_null_player(p_attachment)
|
||||
|
||||
var player = _get_player(p_attachment)
|
||||
|
||||
if player == null:
|
||||
push_warning("Resonate - The event [%s] on bank [%s] can't be instanced; no pooled players available." % [p_event_name, p_bank_label])
|
||||
return _get_null_player(p_attachment)
|
||||
|
||||
var bus = p_bus if p_bus != "" else _get_bus(bank.bus, event.bus)
|
||||
|
||||
player.configure(event.streams, p_reserved, bus, p_poly, event.volume, event.pitch, bank.mode)
|
||||
player.attach_to(p_attachment)
|
||||
|
||||
return player
|
||||
|
||||
|
||||
func _is_player_free(p_player) -> bool:
|
||||
return not p_player.playing and not p_player.reserved
|
||||
|
||||
|
||||
func _get_player_from_pool(p_pool: Array) -> Variant:
|
||||
if p_pool.size() == 0:
|
||||
push_error("Resonate - Player pool has not been initialised. This can occur when calling a [play/instance*] function from [_ready].")
|
||||
return null
|
||||
|
||||
for player in p_pool:
|
||||
if _is_player_free(player):
|
||||
return player
|
||||
|
||||
push_warning("Resonate - Player pool exhausted, consider increasing the pool size in the project settings (Audio/Manager/Pooling) or releasing unused audio stream players.")
|
||||
return null
|
||||
|
||||
|
||||
func _get_player_1d() -> PooledAudioStreamPlayer:
|
||||
return _get_player_from_pool(_1d_players)
|
||||
|
||||
|
||||
func _get_player_2d() -> PooledAudioStreamPlayer2D:
|
||||
return _get_player_from_pool(_2d_players)
|
||||
|
||||
|
||||
func _get_player_3d() -> PooledAudioStreamPlayer3D:
|
||||
return _get_player_from_pool(_3d_players)
|
||||
|
||||
|
||||
func _get_player(p_attachment = null) -> Variant:
|
||||
if ResonateUtils.is_2d_node(p_attachment):
|
||||
return _get_player_2d()
|
||||
|
||||
if ResonateUtils.is_3d_node(p_attachment):
|
||||
return _get_player_3d()
|
||||
|
||||
return _get_player_1d()
|
||||
|
||||
|
||||
func _get_null_player(p_attachment = null) -> Variant:
|
||||
if ResonateUtils.is_2d_node(p_attachment):
|
||||
return null_instance_2d()
|
||||
|
||||
if ResonateUtils.is_3d_node(p_attachment):
|
||||
return null_instance_3d()
|
||||
|
||||
return null_instance()
|
||||
|
||||
|
||||
func _add_player_to_pool(p_player, p_pool) -> Variant:
|
||||
add_child(p_player)
|
||||
|
||||
p_player.released.connect(_on_player_released.bind(p_player))
|
||||
p_player.finished.connect(_on_player_finished.bind(p_player))
|
||||
p_pool.append(p_player)
|
||||
|
||||
return p_player
|
||||
|
||||
|
||||
func _create_player_1d() -> PooledAudioStreamPlayer:
|
||||
return _add_player_to_pool(PooledAudioStreamPlayer.create(), _1d_players)
|
||||
|
||||
|
||||
func _create_player_2d() -> PooledAudioStreamPlayer2D:
|
||||
return _add_player_to_pool(PooledAudioStreamPlayer2D.create(), _2d_players)
|
||||
|
||||
|
||||
func _create_player_3d() -> PooledAudioStreamPlayer3D:
|
||||
return _add_player_to_pool(PooledAudioStreamPlayer3D.create(), _3d_players)
|
||||
|
||||
|
||||
func _on_player_released(p_player: Node) -> void:
|
||||
if p_player.playing:
|
||||
return
|
||||
|
||||
pools_updated.emit()
|
||||
updated.emit()
|
||||
|
||||
|
||||
func _on_player_finished(p_player: Node) -> void:
|
||||
if p_player.reserved:
|
||||
return
|
||||
|
||||
pools_updated.emit()
|
||||
updated.emit()
|
||||
Loading…
Add table
Add a link
Reference in a new issue