Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
24 changes: 24 additions & 0 deletions audio/scheduled_metronome/Perc_MetronomeQuartz_hi.wav.import
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[remap]

importer="wav"
type="AudioStreamWAV"
uid="uid://j8yec16ugbbv"
path="res://.godot/imported/Perc_MetronomeQuartz_hi.wav-812497d02260463d68888c4f5101e271.sample"

[deps]

source_file="res://Perc_MetronomeQuartz_hi.wav"
dest_files=["res://.godot/imported/Perc_MetronomeQuartz_hi.wav-812497d02260463d68888c4f5101e271.sample"]

[params]

force/8_bit=false
force/mono=false
force/max_rate=false
force/max_rate_hz=44100
edit/trim=false
edit/normalize=false
edit/loop_mode=0
edit/loop_begin=0
edit/loop_end=-1
compress/mode=2
22 changes: 22 additions & 0 deletions audio/scheduled_metronome/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Scheduled Metronome Demo

Godot project for showcasing `AudioStreamPlayer.play_scheduled()`. Plays a song
on loop with a metronome.

The metronome sound was recorded by Ludwig Peter Müller in December 2020 under
the "Creative Commons CC0 1.0 Universal" license.

Language: GDScript

Renderer: Compatibility

Check out this demo on the asset library: (TBD)

## Things to try

- Swap between `play` and `play_scheduled` for the metronome ticks.
- Adjust max FPS to showcase its effect on the metronome.

## Screenshots

![Screenshot](screenshots/scheduled-metronome.png)
82 changes: 82 additions & 0 deletions audio/scheduled_metronome/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 37 additions & 0 deletions audio/scheduled_metronome/icon.svg.import
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://neinc785lt3k"
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://icon.svg"
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.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
Binary file added audio/scheduled_metronome/icon.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 34 additions & 0 deletions audio/scheduled_metronome/icon.webp.import
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[remap]

importer="texture"
type="CompressedTexture2D"
uid="uid://cbj2pph8lw003"
path="res://.godot/imported/icon.webp-e94f9a68b0f625a567a797079e4d325f.ctex"
metadata={
"vram_texture": false
}

[deps]

source_file="res://icon.webp"
dest_files=["res://.godot/imported/icon.webp-e94f9a68b0f625a567a797079e4d325f.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
102 changes: 102 additions & 0 deletions audio/scheduled_metronome/main.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
extends Node2D

const SONG_VOLUME_DB = -18

@export_category("Song Settings")
@export var bpm: float = 130
@export var song_length_beats: int = 32

@export_category("Nodes")
@export var max_fps_slider: HSlider
@export var max_fps_spinbox: SpinBox
@export var game_time_label: Label
@export var audio_time_label: Label

@onready var _master_bus_index: int = AudioServer.get_bus_index("Master")

var _tween: Tween
var _scheduled_song_start_time: float
var _scheduled_song_time: float


func _ready() -> void:
_update_max_fps(10)

# Both scheduled and non-scheduled players run simultaneously, but only one
# set is playing audio at a time. By default, the scheduled players are muted.
$SongScheduled.volume_linear = 0
$MetronomeScheduled.volume_linear = 0

# Scheduled players. Schedule for 1 second in the future.
_scheduled_song_start_time = AudioServer.get_absolute_time() + 1
print("Scheduled song starting at ", _scheduled_song_start_time)
$SongScheduled.play_scheduled(_scheduled_song_start_time)
$MetronomeScheduled.start(_scheduled_song_start_time)
_scheduled_song_time = _scheduled_song_start_time

# Non-scheduled players. Wait 1 second, then start playing.
await get_tree().create_timer(1).timeout
var sys_time := Time.get_ticks_usec() / 1000000.0
$Song.play()
$Metronome.start(sys_time)


func _process(_delta: float) -> void:
var abs_time := AudioServer.get_absolute_time()
var game_time := Time.get_ticks_usec() / 1000000.0

# Show the new game/audio times.
game_time_label.text = "Game Time: %.4f" % game_time
audio_time_label.text = "Audio Time: %.4f" % abs_time

var song_length := 60 / bpm * song_length_beats

# If for some reason there isn't a song playing right now (e.g. game is in a
# background tab on web), seek to the correct time and play the song.
if abs_time > _scheduled_song_time + song_length:
var prev_song_loop := floori((abs_time - _scheduled_song_start_time) / song_length)
_scheduled_song_time = _scheduled_song_start_time + prev_song_loop * song_length
$SongScheduled.play_scheduled(abs_time + 0.1, abs_time + 0.1 - _scheduled_song_time)

# Schedule the next song loop manually.
if abs_time > _scheduled_song_time:
var next_song_loop := ceili((abs_time + 0.001 - _scheduled_song_start_time) / song_length)
_scheduled_song_time = _scheduled_song_start_time + next_song_loop * song_length
$SongScheduled.play_scheduled(_scheduled_song_time)


func _update_max_fps(max_fps: int) -> void:
Engine.max_fps = max_fps
ProjectSettings.set("application/run/max_fps", max_fps)
max_fps_slider.value = max_fps
max_fps_spinbox.value = max_fps


func _on_max_fps_h_slider_value_changed(value: float) -> void:
_update_max_fps(int(value))


func _on_max_fps_spin_box_value_changed(value: float) -> void:
_update_max_fps(int(value))


func _on_use_play_scheduled_check_button_toggled(toggled_on: bool) -> void:
if _tween:
_tween.kill()

if toggled_on:
_tween = create_tween().parallel()
_tween.tween_property($Song, "volume_linear", 0, 0.2)
_tween.tween_property($Metronome, "volume_linear", 0, 0.2)
_tween.tween_property($SongScheduled, "volume_linear", db_to_linear(SONG_VOLUME_DB), 0.2)
_tween.tween_property($MetronomeScheduled, "volume_linear", 1, 0.2)
else:
_tween = create_tween().parallel()
_tween.tween_property($SongScheduled, "volume_linear", 0, 0.2)
_tween.tween_property($MetronomeScheduled, "volume_linear", 0, 0.2)
_tween.tween_property($Song, "volume_linear", db_to_linear(SONG_VOLUME_DB), 0.2)
_tween.tween_property($Metronome, "volume_linear", 1, 0.2)


func _on_volume_h_slider_value_changed(value: float) -> void:
AudioServer.set_bus_volume_linear(_master_bus_index, value)
1 change: 1 addition & 0 deletions audio/scheduled_metronome/main.gd.uid
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
uid://mwio0eujos2s
Loading