Skip to content

Commit 88fa7fa

Browse files
Add a sound scheduling demo (scheduled metronome)
1 parent 819d201 commit 88fa7fa

21 files changed

+580
-0
lines changed
31.8 KB
Binary file not shown.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[remap]
2+
3+
importer="wav"
4+
type="AudioStreamWAV"
5+
uid="uid://j8yec16ugbbv"
6+
path="res://.godot/imported/Perc_MetronomeQuartz_hi.wav-812497d02260463d68888c4f5101e271.sample"
7+
8+
[deps]
9+
10+
source_file="res://Perc_MetronomeQuartz_hi.wav"
11+
dest_files=["res://.godot/imported/Perc_MetronomeQuartz_hi.wav-812497d02260463d68888c4f5101e271.sample"]
12+
13+
[params]
14+
15+
force/8_bit=false
16+
force/mono=false
17+
force/max_rate=false
18+
force/max_rate_hz=44100
19+
edit/trim=false
20+
edit/normalize=false
21+
edit/loop_mode=0
22+
edit/loop_begin=0
23+
edit/loop_end=-1
24+
compress/mode=2

audio/scheduled_metronome/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Scheduled Metronome Demo
2+
3+
Godot project for showcasing `AudioStreamPlayer.play_scheduled()`. Plays a song
4+
on loop with a metronome.
5+
6+
The metronome sound was recorded by Ludwig Peter Müller in December 2020 under
7+
the "Creative Commons CC0 1.0 Universal" license.
8+
9+
Language: GDScript
10+
11+
Renderer: Compatibility
12+
13+
Check out this demo on the asset library: (TBD)
14+
15+
## Things to try
16+
17+
- Swap between `play` and `play_scheduled` for the metronome ticks.
18+
- Adjust max FPS to showcase its effect on the metronome.
19+
20+
## Screenshots
21+
22+
![Screenshot](screenshots/scheduled-metronome.png)

audio/scheduled_metronome/icon.svg

Lines changed: 82 additions & 0 deletions
Loading
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[remap]
2+
3+
importer="texture"
4+
type="CompressedTexture2D"
5+
uid="uid://neinc785lt3k"
6+
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
7+
metadata={
8+
"vram_texture": false
9+
}
10+
11+
[deps]
12+
13+
source_file="res://icon.svg"
14+
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
15+
16+
[params]
17+
18+
compress/mode=0
19+
compress/high_quality=false
20+
compress/lossy_quality=0.7
21+
compress/hdr_compression=1
22+
compress/normal_map=0
23+
compress/channel_pack=0
24+
mipmaps/generate=false
25+
mipmaps/limit=-1
26+
roughness/mode=0
27+
roughness/src_normal=""
28+
process/fix_alpha_border=true
29+
process/premult_alpha=false
30+
process/normal_map_invert_y=false
31+
process/hdr_as_srgb=false
32+
process/hdr_clamp_exposure=false
33+
process/size_limit=0
34+
detect_3d/compress_to=1
35+
svg/scale=1.0
36+
editor/scale_with_editor_scale=false
37+
editor/convert_colors_with_editor_theme=false

audio/scheduled_metronome/icon.webp

1.96 KB
Loading
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[remap]
2+
3+
importer="texture"
4+
type="CompressedTexture2D"
5+
uid="uid://cbj2pph8lw003"
6+
path="res://.godot/imported/icon.webp-e94f9a68b0f625a567a797079e4d325f.ctex"
7+
metadata={
8+
"vram_texture": false
9+
}
10+
11+
[deps]
12+
13+
source_file="res://icon.webp"
14+
dest_files=["res://.godot/imported/icon.webp-e94f9a68b0f625a567a797079e4d325f.ctex"]
15+
16+
[params]
17+
18+
compress/mode=0
19+
compress/high_quality=false
20+
compress/lossy_quality=0.7
21+
compress/hdr_compression=1
22+
compress/normal_map=0
23+
compress/channel_pack=0
24+
mipmaps/generate=false
25+
mipmaps/limit=-1
26+
roughness/mode=0
27+
roughness/src_normal=""
28+
process/fix_alpha_border=true
29+
process/premult_alpha=false
30+
process/normal_map_invert_y=false
31+
process/hdr_as_srgb=false
32+
process/hdr_clamp_exposure=false
33+
process/size_limit=0
34+
detect_3d/compress_to=1

audio/scheduled_metronome/main.gd

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
extends Node2D
2+
3+
const SONG_VOLUME_DB = -18
4+
5+
@export_category("Song Settings")
6+
@export var bpm: float = 130
7+
@export var song_length_beats: int = 32
8+
9+
@export_category("Nodes")
10+
@export var max_fps_slider: HSlider
11+
@export var max_fps_spinbox: SpinBox
12+
@export var game_time_label: Label
13+
@export var audio_time_label: Label
14+
15+
@onready var _master_bus_index: int = AudioServer.get_bus_index("Master")
16+
17+
var _tween: Tween
18+
var _scheduled_song_start_time: float
19+
var _scheduled_song_time: float
20+
21+
22+
func _ready() -> void:
23+
_update_max_fps(10)
24+
25+
# Both scheduled and non-scheduled players run simultaneously, but only one
26+
# set is playing audio at a time. By default, the scheduled players are muted.
27+
$SongScheduled.volume_linear = 0
28+
$MetronomeScheduled.volume_linear = 0
29+
30+
# Scheduled players. Schedule for 1 second in the future.
31+
_scheduled_song_start_time = AudioServer.get_absolute_time() + 1
32+
print("Scheduled song starting at ", _scheduled_song_start_time)
33+
$SongScheduled.play_scheduled(_scheduled_song_start_time)
34+
$MetronomeScheduled.start(_scheduled_song_start_time)
35+
_scheduled_song_time = _scheduled_song_start_time
36+
37+
# Non-scheduled players. Wait 1 second, then start playing.
38+
await get_tree().create_timer(1).timeout
39+
var sys_time := Time.get_ticks_usec() / 1000000.0
40+
$Song.play()
41+
$Metronome.start(sys_time)
42+
43+
44+
func _process(_delta: float) -> void:
45+
var abs_time := AudioServer.get_absolute_time()
46+
var game_time := Time.get_ticks_usec() / 1000000.0
47+
48+
# Show the new game/audio times.
49+
game_time_label.text = "Game Time: %.4f" % game_time
50+
audio_time_label.text = "Audio Time: %.4f" % abs_time
51+
52+
var song_length := 60 / bpm * song_length_beats
53+
54+
# If for some reason there isn't a song playing right now (e.g. game is in a
55+
# background tab on web), seek to the correct time and play the song.
56+
if abs_time > _scheduled_song_time + song_length:
57+
var prev_song_loop := floori((abs_time - _scheduled_song_start_time) / song_length)
58+
_scheduled_song_time = _scheduled_song_start_time + prev_song_loop * song_length
59+
$SongScheduled.play_scheduled(abs_time + 0.1, abs_time + 0.1 - _scheduled_song_time)
60+
61+
# Schedule the next song loop manually.
62+
if abs_time > _scheduled_song_time:
63+
var next_song_loop := ceili((abs_time + 0.001 - _scheduled_song_start_time) / song_length)
64+
_scheduled_song_time = _scheduled_song_start_time + next_song_loop * song_length
65+
$SongScheduled.play_scheduled(_scheduled_song_time)
66+
67+
68+
func _update_max_fps(max_fps: int) -> void:
69+
Engine.max_fps = max_fps
70+
ProjectSettings.set("application/run/max_fps", max_fps)
71+
max_fps_slider.value = max_fps
72+
max_fps_spinbox.value = max_fps
73+
74+
75+
func _on_max_fps_h_slider_value_changed(value: float) -> void:
76+
_update_max_fps(int(value))
77+
78+
79+
func _on_max_fps_spin_box_value_changed(value: float) -> void:
80+
_update_max_fps(int(value))
81+
82+
83+
func _on_use_play_scheduled_check_button_toggled(toggled_on: bool) -> void:
84+
if _tween:
85+
_tween.kill()
86+
87+
if toggled_on:
88+
_tween = create_tween().parallel()
89+
_tween.tween_property($Song, "volume_linear", 0, 0.2)
90+
_tween.tween_property($Metronome, "volume_linear", 0, 0.2)
91+
_tween.tween_property($SongScheduled, "volume_linear", db_to_linear(SONG_VOLUME_DB), 0.2)
92+
_tween.tween_property($MetronomeScheduled, "volume_linear", 1, 0.2)
93+
else:
94+
_tween = create_tween().parallel()
95+
_tween.tween_property($SongScheduled, "volume_linear", 0, 0.2)
96+
_tween.tween_property($MetronomeScheduled, "volume_linear", 0, 0.2)
97+
_tween.tween_property($Song, "volume_linear", db_to_linear(SONG_VOLUME_DB), 0.2)
98+
_tween.tween_property($Metronome, "volume_linear", 1, 0.2)
99+
100+
101+
func _on_volume_h_slider_value_changed(value: float) -> void:
102+
AudioServer.set_bus_volume_linear(_master_bus_index, value)

audio/scheduled_metronome/main.gd.uid

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://mwio0eujos2s

0 commit comments

Comments
 (0)