Timer for a Music Player

Godot Version

4.2

Question

I am trying at add a Timer for the remaining time for the song playing. As of now I forced the label to see the argument as a string but produces a float that goes up from 0 to 0.00000etc .

Edited to better show my current spot in this.
I don’t know if this helps or just linking to it so I will do both

https://github.com/KindaWrks/Music-Player

extends Node2D

@onready var fd_open = $FD_OPEN

@onready var music_label = $MusicLabel
@onready var music_time_label = $MusicTimeLabel
@onready var music_total_time = $MusicTotalTimeLabel

@export var audio_bus_name := "Master" #Makes the var Master audio bus
@onready var _bus := AudioServer.get_bus_index(audio_bus_name) #Sets bus index to Master

# Called when the node enters the scene tree for the first time.
func _ready():
	fd_o_filters()
	fd_open.visible = true
	music_label.visible = false

func fd_o_filters():
	fd_open.current_dir = "/"  #Set current dir as Root
	fd_open.add_filter("*.mp3 ; Music") #Set filter for MP3 files

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta):
	music_label.text = fd_open.current_file.get_basename() #Gets the current file and removes the .MP3
	music_time_label.text = str(int($AudioStreamPlayer.get_playback_position())) #Make time count in int rather then flaot
	
func _on_fd_open_file_selected(path):
	var snd_file = FileAccess.open(path, FileAccess.READ) #Open path and reaf from the file
	var stream = AudioStreamMP3.new() #Create a bew MP3 Audio stream
	stream.data = snd_file.get_buffer(snd_file.get_length()) # Load entire song into memory(not ideal)
	snd_file.close() #Close file.
	$AudioStreamPlayer.stream = stream  #The loaded song in memeory
	$AudioStreamPlayer.play()
	music_label.visible = true
	music_total_time.text = str(int($AudioStreamPlayer.stream.get_length()))


func _on_h_slider_value_changed(value: float):
	AudioServer.set_bus_volume_db(_bus,linear_to_db(value)) #Control volume as a float

Not sure if I understand the problem. get_playback_position() does return a float, and yes, if you want to show that value on a Label you have to explicitly cast it into a string first, as with all numeric values. If you want to limit the amount of digits after the dot, use a format string, e.g. for two digits do:

music_time_label.text = "%.2f" % [$AudioStreamPlayer.get_playback_position()]

Now, in order to get the remaining time of the track, you’d only have to get the overall length of the stream with get_length() and then subtract the current position in the stream from it:

music_time_label.text = "%.2f" % [$AudioStreamPlayer.stream.get_length() - $AudioStreamPlayer.get_playback_position()]

And yes, if you’re only interested in full seconds, just cast it into a int at the end.

1 Like

Hi thank you for the answers, I guess I didn’t fix the top post as well as I thought.
One of my questions was indeed time remaining, I also found out str, int for whole seconds.

I was trying to declare the time as 0:00 like a modern day player. I think I have a basic idea for the custom setup where minutes are like % 60/60 … At least that is what I got from it all.

1 Like

I see why I never got the timer to work as I was putting it raw in proceses. I don’t see how I overlooked it. I needed a if statement/function for audio then display the stringed integer.

Though now I am on to my next task how to make the audiostreamplayer work with an’ array and index. I have had luck with array/index when I feed it one song. Though if I add multiple to the array it crashes or index 0s.

Correct me if I’m wrong but I need a way to always make a new player and feed the current index?

I’m not sure, I fully comprehend what you’re trying to do. Maybe post the code for what you’re trying to do? :slight_smile:

Sorry, i was just happy to figure out what stopped my label earlier was just idiocy. I was also relaying I was on to my new enemy the error packedstringarray or index 0.

This is not on the github as this is the test/scratch code.
I try to make it play the next song in the array via the index, kinda like a song queue. I have tried a few ways such as file new or mp3 new.

I don’t know when I last messed with this scratch in the last few days. I thought I knew how I was handling the change thourgh increasing the index. The play button for “files” is not hooked up as I was testing single file as a autoplay.

extends Node2D
@onready var btnshow = $Buttonshow #to reopen fd_open
@onready var fd_open = $FD_OPEN
@onready var music_label = $MusicLabel
@onready var music_time_label = $MusicTimeLabel
@onready var musicarray : Array = [] #start array blank array
@onready var musicindex = 0 #intial index for track progression

@export var audio_bus_name := "Master" #Makes the var Master audio bus
@onready var _bus := AudioServer.get_bus_index(audio_bus_name) #Sets bus index to Master

# Called when the node enters the scene tree for the first time.
func _ready():
	fd_o_filters()
	fd_open.visible = true
	music_label.visible = false

	
func fd_o_filters():
	fd_open.current_dir = "/"  #Set current dir as Root
	fd_open.add_filter("*.mp3 ; Music") #Set filter for MP3 files

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta):
	
	if $AudioStreamPlayer.playing:
		music_label.text = str(musicarray).get_file().get_basename() #Gets the current index of array and removes the .MP3
		music_time_label.text = str(int($AudioStreamPlayer.get_playback_position()))
		print(musicarray[musicindex])
	
	
func _on_fd_open_file_selected(path):
	var snd_file = FileAccess.open(path, FileAccess.READ) #Open path and reaf from the file
	var stream = AudioStreamMP3.new() #Create a bew MP3 Audio stream
	stream.data = snd_file.get_buffer(snd_file.get_length()) # Load entire song into memory(not ideal)
	snd_file.close() #Close file.
	$AudioStreamPlayer.stream = stream  #The loaded song in memeory
	$AudioStreamPlayer.play()
	music_label.visible = true
	musicarray.append(path)
	musicindex += 1
	if musicindex > musicarray.size() - 1:
		musicindex = 0
		

func _on_h_slider_value_changed(value: float):
	AudioServer.set_bus_volume_db(_bus,linear_to_db(value)) #Control volume as a float


func _on_buttonshow_pressed(): #reopen fd_open
	fd_open.visible = true


func _on_fd_open_files_selected(paths): #when set to files without audiostream adds all to array
	music_label.visible = true
	musicarray.append(paths)
	musicindex += 1
	if musicindex > musicarray.size() - 1:
		musicindex = 0
		print(musicarray[musicindex])

func music_index(): #indexs the musicarray
	if $AudioStreamPlayer.finished():
		musicindex += 1
	if musicindex > musicarray.size() - 1:
		musicindex = 0
		print(musicarray[musicindex])

-edit 3- Worked on the non-srcatch version and fixed it up to use the musicarray and music index again. I also incorparated the song_list and song choice when slecting/clicking. It seems like each time I ask a question now I seem to come up with a answer and look foolish.


extends Node2D

@onready var fd_open = $FD_OPENfiles

@onready var music_time_label = $MusicTimeLabel
@onready var music_total_time = $MusicTotalTimeLabel

@export var audio_bus_name := "Master" #Makes the var Master audio bus
@onready var _bus := AudioServer.get_bus_index(audio_bus_name) #Sets bus index to Master

var musicarray = [] # Initialize array only
var musicindex = 0

# Called when the node enters the scene tree for the first time.
func _ready():
	fd_o_filters()
	fd_open.visible = true

func fd_o_filters():
	fd_open.current_dir = "/"  #Set current dir as Root
	fd_open.add_filter("*.mp3 ; Music") #Set filter for MP3 files

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta):
	
	if $AudioStreamPlayer.playing: #Make time count down in int rather then float and show total time
		music_time_label.text = str(int($AudioStreamPlayer.stream.get_length()) - int($AudioStreamPlayer.get_playback_position()))
		music_total_time.text = str(int($AudioStreamPlayer.stream.get_length()))
	print(musicarray)
	
	
	# Check if the song ended and play the next song in the queue
	if not $AudioStreamPlayer.playing and musicarray.size() > 0:
		play_next_song()


func _on_fd_open_files_selected(paths):
	for path in paths:
		var snd_file = FileAccess.open(path, FileAccess.READ) # Open path and read from the file
		var stream = AudioStreamMP3.new() # Create a new MP3 Audio stream
		stream.data = snd_file.get_buffer(snd_file.get_length()) # Load entire song into memory(not ideal)
		snd_file.close() # Close file.
		$AudioStreamPlayer.stream = stream  # The loaded song in memory
		$AudioStreamPlayer.play()

		# Add the selected song to the queue
		musicarray.append(path)
		
		#Add song list
		var file_name_without_extension = path.get_file().get_basename()
		$song_list.add_item(file_name_without_extension)

func play_next_song():
	var next_song_path = musicarray[musicindex] # Get the next song from the queue
	var snd_file = FileAccess.open(next_song_path, FileAccess.READ) #Open path and read from the file
	var stream = AudioStreamMP3.new() #Create a new MP3 Audio stream
	stream.data = snd_file.get_buffer(snd_file.get_length()) # Load entire song into memory(not ideal)
	snd_file.close() #Close file.
	$AudioStreamPlayer.stream = stream  #The loaded song in memory
	$AudioStreamPlayer.play()

func _on_buttonshow_pressed(): #Show Filedialog
	fd_open.visible = true
	
func _on_h_slider_value_changed(value: float):
	AudioServer.set_bus_volume_db(_bus,linear_to_db(value)) #Control volume as a float

# Called when an item in the song list is selected
func _on_song_list_item_selected(index):
	if index < musicarray.size():
		var selected_song_path = musicarray[index]
		play_song(selected_song_path)

# Function to play a selected song
func play_song(song_path):
	var snd_file = FileAccess.open(song_path, FileAccess.READ)
	var stream = AudioStreamMP3.new()
	stream.data = snd_file.get_buffer(snd_file.get_length())
	snd_file.close()
	$AudioStreamPlayer.stream = stream
	$AudioStreamPlayer.play()