WIP: implementing a music mixer
This commit is contained in:
parent
48b4596f50
commit
8a5f05cd77
|
|
@ -0,0 +1,21 @@
|
|||
@tool
|
||||
class_name AudioTrack extends Resource
|
||||
|
||||
@export var audio: AudioStream
|
||||
@export var bpm: int = 120
|
||||
@export var jump_interval: int
|
||||
@export var offset: float = 0
|
||||
@export_placeholder("\"LOOP\" or track name.") var advance_to: String
|
||||
|
||||
@export_group("Transition Settings")
|
||||
@export var smoothing: float = 1
|
||||
@export var transition_in_type: MixedAudioStream.TransIn = MixedAudioStream.TransIn.HARD
|
||||
@export var transition_out_type: MixedAudioStream.TransOut = MixedAudioStream.TransOut.HARD
|
||||
@export var loop_type: MixedAudioStream.Loop = MixedAudioStream.Loop.HARD_IN_OUT
|
||||
@export var jump_type: MixedAudioStream.Jump = MixedAudioStream.Jump.SOFT
|
||||
|
||||
@export_group("Beat Markers")
|
||||
@export var intro_end: int = -1
|
||||
@export var loop_in: int = -1
|
||||
@export var loop_out: int = -1
|
||||
@export var outro_start: int = -1
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://bso71xkb3xqnb
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
@tool
|
||||
class_name BPMTimer extends Timer
|
||||
|
||||
@export var bpm: float = 120:
|
||||
set(beats):
|
||||
bpm = beats
|
||||
beat_length = bpm / 60.0
|
||||
var beat_length: float = (120.0/60.0)
|
||||
@export var beats_per_bar: int = 4
|
||||
@export var grid_offset: float = 0
|
||||
var sync_to: AudioStreamPlayback
|
||||
var current_beat: int
|
||||
var current_bar: int
|
||||
|
||||
signal on_beat(beat_count: int)
|
||||
signal on_bar(bar_count: int)
|
||||
|
||||
@warning_ignore("shadowed_variable")
|
||||
func _init(bpm:float = 120, beats_per_bar:int = 4, grid_offset:float = 0, sync_to_playback:AudioStreamPlayback = null) -> void:
|
||||
self.bpm = bpm
|
||||
self.beats_per_bar = beats_per_bar
|
||||
self.grid_offset = grid_offset
|
||||
self.sync_to = sync_to_playback
|
||||
|
||||
func _ready() -> void:
|
||||
start(0.5)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if not is_stopped():
|
||||
if sync_to != null:
|
||||
if not sync_to.is_playing():
|
||||
stop()
|
||||
if fmod(sync_to.get_playback_position()-grid_offset + delta, beat_length) < delta * 2.0:
|
||||
_on_beat()
|
||||
_last_beat_timing = sync_to.get_playback_position()
|
||||
else:
|
||||
if not Engine.is_editor_hint(): print(time_left)
|
||||
|
||||
func start(time_sec: float = 0, starting_beat: int = 0, starting_bar: int = 0, sync_to_playback:AudioStreamPlayback = null) -> void:
|
||||
if starting_bar == 0 and starting_beat > 0: starting_bar = starting_beat / beats_per_bar
|
||||
current_beat = starting_beat - 1
|
||||
current_bar = starting_bar - 1
|
||||
_last_bar = starting_beat - ( starting_beat % beats_per_bar )
|
||||
|
||||
wait_time = beat_length
|
||||
grid_offset = time_sec
|
||||
|
||||
if not sync_to_playback == null: sync_to = sync_to_playback
|
||||
|
||||
if sync_to != null:
|
||||
await get_tree().process_frame
|
||||
if sync_to.is_playing():
|
||||
on_beat.connect(_on_beat)
|
||||
return
|
||||
super.start()
|
||||
else:
|
||||
await get_tree().create_timer(time_sec).timeout
|
||||
_on_beat()
|
||||
super.start()
|
||||
|
||||
func stop():
|
||||
if timeout.get_connections().has(_on_beat):
|
||||
timeout.disconnect(_on_beat)
|
||||
super.stop()
|
||||
|
||||
var _last_bar = 0
|
||||
|
||||
func _on_beat():
|
||||
current_beat += 1
|
||||
on_beat.emit(current_beat)
|
||||
if current_beat - _last_bar > beats_per_bar:
|
||||
_last_bar = current_bar
|
||||
current_bar += 1
|
||||
on_bar.emit(current_bar)
|
||||
|
||||
var _last_beat_timing
|
||||
func get_beat_progress(from_beat:int = -1, to_beat:int = -1, countdown:bool = false) -> float:
|
||||
if is_stopped(): return 0 if not countdown else 1
|
||||
if from_beat == -1: from_beat == current_beat
|
||||
if to_beat == -1: to_beat == current_beat +1
|
||||
assert(to_beat > from_beat)
|
||||
if current_beat <= from_beat: return 0 if not countdown else 1
|
||||
if current_beat >= to_beat: return 1 if not countdown else 0
|
||||
var beat_range: float = from_beat - to_beat
|
||||
var beat_progress: float = (current_beat - to_beat) / beat_range
|
||||
if sync_to == null:
|
||||
var result: float = beat_progress + (time_left / bpm) / beat_range
|
||||
return result if not countdown else 1 - result
|
||||
else:
|
||||
var result: float = beat_progress + (sync_to.get_playback_position() - _last_beat_timing) / bpm
|
||||
return result if not countdown else 1 - result
|
||||
return 0
|
||||
|
||||
func get_bar_progress(from_bar:int = 0, to_bar:int = -1, countdown:bool = false) -> float:
|
||||
if from_bar == -1: from_bar == current_beat
|
||||
if to_bar == -1: to_bar == current_beat +1
|
||||
return get_beat_progress(from_bar * beats_per_bar, to_bar * beats_per_bar)
|
||||
|
||||
func get_time_to_beat(to_beat:int = -1) -> float:
|
||||
if to_beat == -1: to_beat == current_beat +1
|
||||
var result
|
||||
if sync_to == null:
|
||||
result = time_left
|
||||
else:
|
||||
result = sync_to.get_playback_position() - _last_beat_timing
|
||||
|
||||
return result + (to_beat - current_bar + 1) / bpm
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://7v24sdisnbia
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
class_name FillerTrack extends Resource
|
||||
|
||||
@export var audio: AudioStream
|
||||
@export var bpm: int
|
||||
|
||||
|
||||
@export_flags_3d_render var blend_from
|
||||
@export_flags_3d_render var blend_to
|
||||
|
||||
@export var offset: float = 0
|
||||
|
||||
@export_group("Transition Settings")
|
||||
@export var smoothing: float = 1
|
||||
@export var transition_in_type: MixedAudioStream.TransIn
|
||||
@export var transition_out_type: MixedAudioStream.TransOut
|
||||
@export var previous_out_override: MixedAudioStream.TransOut
|
||||
@export var next_in_override: MixedAudioStream.TransIn
|
||||
|
||||
@export_group("Beat Markers")
|
||||
@export var fill_in: int
|
||||
@export var fill_out: int
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://qgitde4nibng
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
@tool
|
||||
class_name MixedAudioHelper extends AudioStreamPlayer
|
||||
|
||||
enum TriggerPoint {
|
||||
IMMEDIATE,
|
||||
INTRO_END,
|
||||
LOOP_IN,
|
||||
LOOP_OUT,
|
||||
OUTRO
|
||||
}
|
||||
|
||||
#FIXME: I should consider adding a neutral scene to the ids enum for each room. Maybe we can work something out based on the currently selected room here, but as it stands now it is impossible to select the main theme other than intentionally selecting something unintended.
|
||||
@export var play_next: Scenes.id:
|
||||
set(next):
|
||||
if next == 0:
|
||||
play_next = 0
|
||||
return
|
||||
play_next = next
|
||||
|
||||
func get_playback_id_from_scene(scene: int) -> int:
|
||||
match scene:
|
||||
Scenes.id.ADULT_DND: return 1
|
||||
Scenes.id.ADULD_VOLUNTARY: return 2
|
||||
Scenes.id.ADULD_CHRISTMAS: return 3
|
||||
Scenes.id.ADULT_EATING: return 4
|
||||
Scenes.id.ADULT_UNI: return 5
|
||||
Scenes.id.ADULT_THERAPY: return 6
|
||||
Scenes.id.ADULT_BURNOUT: return 7
|
||||
_: return 0
|
||||
|
||||
@export var actually_playing: bool = false:
|
||||
set(play):
|
||||
actually_playing = play
|
||||
if actually_playing:
|
||||
self.play()
|
||||
else:
|
||||
stop()
|
||||
@export var actual_stream: MixedAudioStream
|
||||
|
||||
var _playback: AudioStreamPlaybackPolyphonic
|
||||
var main_stream_id: int = -1:
|
||||
set(stream_id):
|
||||
main_stream_id = stream_id
|
||||
if main_stream_id == -1:
|
||||
stop()
|
||||
else:
|
||||
main_stream_playback_id = _playback.play_stream(actual_stream.get_stream_by_id(main_stream_id))
|
||||
var main_stream_playback_id:int = -1
|
||||
var transition_stream_id: int
|
||||
var transition_stream_playback_id:int = -1
|
||||
var next_stream_id: int
|
||||
var next_stream_playback_id:int = -1
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
stream = AudioStreamPolyphonic.new()
|
||||
|
||||
func play(from_position: float = 0.0):
|
||||
print("got called")
|
||||
super.play(from_position)
|
||||
self._play(from_position)
|
||||
|
||||
func queue_trigger(stream_id: int, point: TriggerPoint, trigger: Callable):
|
||||
pass
|
||||
|
||||
func loop_back():
|
||||
pass
|
||||
|
||||
func transition_trigger():
|
||||
pass
|
||||
|
||||
func transition_start():
|
||||
pass
|
||||
|
||||
func transition_end():
|
||||
#make new
|
||||
pass
|
||||
|
||||
func _play(from_position: float = 0.0):
|
||||
_playback = get_stream_playback()
|
||||
|
||||
main_stream_id = get_playback_id_from_scene(play_next)
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://cmp8dth4cvo28
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
@tool
|
||||
class_name MixedAudioStream extends AudioStream
|
||||
|
||||
enum TransIn {
|
||||
HARD,
|
||||
FROM_START,
|
||||
SOFT
|
||||
}
|
||||
|
||||
enum TransOut {
|
||||
HARD,
|
||||
TO_END,
|
||||
SOFT
|
||||
}
|
||||
|
||||
enum Loop {
|
||||
HARD_IN_OUT,
|
||||
HARD_IN_TO_END,
|
||||
HARD_IN_SOFT_END,
|
||||
HARD_OUT
|
||||
}
|
||||
|
||||
enum Jump {
|
||||
HARD,
|
||||
SOFT
|
||||
}
|
||||
|
||||
@export var tracks: Array[AudioTrack]:
|
||||
set(dict):
|
||||
tracks = dict
|
||||
@export var transitions: Array[FillerTrack]
|
||||
|
||||
var _playback: AudioStreamPlaybackPolyphonic
|
||||
|
||||
func is_meta_stream():
|
||||
return true
|
||||
|
||||
func is_monophonic():
|
||||
return false
|
||||
|
||||
func initialize_mix(from_position: float, playback: AudioStreamPlaybackPolyphonic):
|
||||
_playback = playback
|
||||
|
||||
func get_stream_by_id(id: int) -> AudioStream:
|
||||
return tracks[id].audio
|
||||
|
||||
func fadeout(stream_id: int, delay: float):
|
||||
var tween: Tween
|
||||
tween = _playback.pla
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://c05ftj6kxhpil
|
||||
Loading…
Reference in New Issue