Initial untested prototype of AmbienceInterpolator, a class for crossfading between audio streams in an array representing different stages or magnitudes of the same general category of ambience.
This commit is contained in:
parent
30dcb94548
commit
e4c6ff5e89
|
@ -0,0 +1,126 @@
|
|||
class_name AmbienceInterpolator extends Node
|
||||
## Interpolates between multiple ambience streams.
|
||||
|
||||
## Audio fade-out target.
|
||||
const AUDIO_FADE_MIN_VOLUME: float = -20.0
|
||||
## Default audio transition time.
|
||||
const DEFAULT_AUDIO_FADE: float = 1.0
|
||||
|
||||
## Audio bus.
|
||||
@export var bus: StringName
|
||||
## Array of ambience streams to interpolate between.
|
||||
##
|
||||
## If an element is a sub-array, its elements in turn play simultaneously.
|
||||
@export var streams: Array = []
|
||||
|
||||
## Tween channel for interpolation index.
|
||||
@onready var _tween_channel := TweenChannel.make_replacing()
|
||||
|
||||
## Array of audio players, one for each ambience stream.
|
||||
var _players: Array = []
|
||||
## Current interpolation index.
|
||||
##
|
||||
## This value times streams.size() will be offset by +1
|
||||
## from the value whose ceil and ceil-1
|
||||
## will actually be used to index the arrays.
|
||||
## For example, if _ii == 2.5/streams.size(),
|
||||
## then array indices 1 and 2 will be used,
|
||||
## not array indices 2 and 3.
|
||||
## If _ii < 1.0/streams.size(),
|
||||
## it interpolates between silence and array index 0.
|
||||
var _ii: float = 0.0
|
||||
|
||||
## Creates an audio player for each audio stream.
|
||||
func _ready() -> void:
|
||||
for elem in streams:
|
||||
if elem is Array:
|
||||
var mapping: Array = []
|
||||
_players.push_back(mapping)
|
||||
for stream in elem:
|
||||
assert(stream is AudioStream)
|
||||
var player := AudioStreamPlayer.new()
|
||||
add_child(player)
|
||||
mapping.push_back(player)
|
||||
player.bus = bus
|
||||
player.stream = stream
|
||||
else:
|
||||
assert(elem is AudioStream)
|
||||
var player := AudioStreamPlayer.new()
|
||||
add_child(player)
|
||||
_players.push_back(player)
|
||||
player.bus = bus
|
||||
player.stream = elem
|
||||
|
||||
## Getter for interpolation index.
|
||||
func get_interpolation_index() -> float:
|
||||
return _ii
|
||||
|
||||
## Sets interpolation index and adjusts audio player levels accordingly.
|
||||
func set_interpolation_index(ii: float) -> void:
|
||||
# Calculate interpolation factor and array indices.
|
||||
var scaled: float = ii*_players.size()
|
||||
var interp_fact: float = scaled - floorf(scaled)
|
||||
var i_hi: int = ceili(scaled) - 1
|
||||
if i_hi >= _players.size():
|
||||
i_hi = _players.size() - 1
|
||||
var i_lo: int = i_hi - 1
|
||||
# Get audio players from array.
|
||||
var p_hi: Variant = null
|
||||
var p_lo: Variant = null
|
||||
if i_hi >= 0:
|
||||
p_hi = _players[i_hi]
|
||||
if i_lo >= 0:
|
||||
p_lo = _players[i_lo]
|
||||
# Calculate volumes to set.
|
||||
var v_lo: float = lerpf(0.0, AUDIO_FADE_MIN_VOLUME, interp_fact)
|
||||
var v_hi: float = lerpf(AUDIO_FADE_MIN_VOLUME, 0.0, interp_fact)
|
||||
# Set audio player volumes and start audio players.
|
||||
if p_lo is Array:
|
||||
for player in p_lo:
|
||||
assert(player is AudioStreamPlayer)
|
||||
player.volume_db = v_lo
|
||||
if not player.playing:
|
||||
player.play()
|
||||
elif p_lo != null:
|
||||
assert(p_lo is AudioStreamPlayer)
|
||||
p_lo.volume_db = v_lo
|
||||
if not p_lo.playing:
|
||||
p_lo.play()
|
||||
if p_hi is Array:
|
||||
for player in p_hi:
|
||||
assert(player is AudioStreamPlayer)
|
||||
player.volume_db = v_hi
|
||||
if not player.playing:
|
||||
player.play()
|
||||
elif p_hi != null:
|
||||
assert(p_hi is AudioStreamPlayer)
|
||||
p_hi.volume_db = v_hi
|
||||
if not p_hi.playing:
|
||||
p_hi.play()
|
||||
# Stop every audio player we have that isn't one of the two requested.
|
||||
for elem in _players:
|
||||
if elem is Array:
|
||||
for player in elem:
|
||||
assert(player is AudioStreamPlayer)
|
||||
if player != p_lo and player != p_hi:
|
||||
player.volume_db = AUDIO_FADE_MIN_VOLUME
|
||||
if player.playing:
|
||||
player.stop()
|
||||
else:
|
||||
assert(elem is AudioStreamPlayer)
|
||||
if elem != p_lo and elem != p_hi:
|
||||
elem.volume_db = AUDIO_FADE_MIN_VOLUME
|
||||
if elem.playing:
|
||||
elem.stop()
|
||||
# Update stored value of interpolation index.
|
||||
_ii = ii
|
||||
|
||||
## Tweens the interpolation index to the given target over time.
|
||||
func interpolate(target: float, fade: float = DEFAULT_AUDIO_FADE) -> void:
|
||||
var tween := await _tween_channel.create_tween(self)
|
||||
tween.tween_method(
|
||||
set_interpolation_index,
|
||||
get_interpolation_index(),
|
||||
target, fade
|
||||
)
|
||||
await _tween_channel.sync(tween)
|
Loading…
Reference in New Issue