Help me, mp3 player

Godot Version

4.2

Question

Excuse me but a few weeks ago I came asking for someone who could help me make a music player… sorry for asking for help again :pensive:, I will give more details if someone offers to help me

Usually you give some details first, so people know how and if they can assist you. :slight_smile:

It’s just that, as I had said before, I didn’t want to be accused of spam… but well, I’ll get to the point, the problem is the fileDialog, you will see the template I downloaded has a folder which is the one assigned the path to reproduce The music (it’s the one you see in the screenshot with those 2 songs) came with a default song, I realized that if I added another one to that same folder it can also be played… but that’s just the problem, everything I have to do from the godot editor… I tried exporting the game as it was and the situation gets worse… another detail is that I realized that the fieldialog does not allow you to delete copy and paste files or make others load if I drag them…

Can you tick “Use Native Dialog” in the FileDialog properties? You might also want to change it’s access mode to “File System” to access non-exported/godot files

The problem when I activate “native dialog” is that it doesn’t work well for me, for example it doesn’t want to close when I touch “cancel”, and I already tried activating “file system”, but that doesn’t help either, because the chosen mp3 format It doesn’t play in-game, do you need to see the script?

Maybe it needs a function attached to canceled

Certainly a script would help, I believe something must be loaded wrong for one mp3 to work opposed to another.

extends Node2D

@onready var spec = AudioServer.get_bus_effect_instance(0,0)

var listSongRoute=[]
var listSongName=[]

var def = 20

var total_w = 300
var total_h = 500

var min_frec = 20
var max_frec = 1000

var MIN_DB = 60

var songCar = 0

var histogram = []

var minute: float=0.0
var hour=0 

func _ready():
	dir_contents("res://music/")#extends Node2D

@onready var spec = AudioServer.get_bus_effect_instance(0,0)

var listSongRoute=[]
var listSongName=[]

var def = 20

var total_w = 300
var total_h = 500

var min_frec = 20
var max_frec = 1000

var MIN_DB = 60

var songCar = 0

var histogram = []

var minute: float=0.0
var hour=0 

func _ready():
	dir_contents("res://music/")#The .pm3 songs are loaded in the chosen path
	for i in  range(def):#initialize the histogram
		histogram.append(0)

@warning_ignore("unused_parameter")
func _process(delta):
	var freq = min_frec
	@warning_ignore("integer_division")
	var interval = (max_frec -min_frec) / def
	for i in range(def):
		var mag = spec.get_magnitude_for_frequency_range(freq, freq+interval)
		mag = linear_to_db(mag.length())
		histogram[i] = mag
		freq += interval
		queue_redraw()

func secTranform(time:int)->String:#Transformations for seconds and minutes
	var sec = time % 60
	@warning_ignore("integer_division", "shadowed_variable")
	var minute = (time / 60) % 60
	if sec >= 60:
		@warning_ignore("integer_division")
		minute += sec / 60
		sec %= 60
	return str(int(minute)).pad_zeros(2) + ":" + str(sec).pad_zeros(2)

func _draw():
	var sec_inSound = $AudioStreamPlayer.get_playback_position()
	$LblTime.text = secTranform(int(sec_inSound))
	if $AudioStreamPlayer.playing== true: $HSlider.value = sec_inSound
	var draw_pos = Vector2(0,0)
	@warning_ignore("integer_division")
	var w_interval = total_w / def
	if $AudioStreamPlayer.stream_paused == false:
		draw_line(Vector2(0, -total_h), Vector2(0, -total_h), Color.CRIMSON, 12.0,true)
		for i in range(def):
			if i> 4 and i<=14:
				draw_line(draw_pos, draw_pos+ Vector2(0, histogram[i]), Color.AQUA,12.0,true)
				draw_pos.x += w_interval
			elif  i>14:
				draw_line(draw_pos, draw_pos+ Vector2(0, histogram[i]), Color.DARK_BLUE,12.0,true)
				draw_pos.x += w_interval
			else :
				draw_line(draw_pos, draw_pos+ Vector2(0, histogram[i]), Color.DEEP_PINK,12.0,true)
				draw_pos.x += w_interval
	else:
		pass

func preloadSong(i):#load the songs
	var song
	var songSeconds
	if i <= listSongRoute.size()-1:
		var songPath = listSongRoute[i]
		$LblName.text = listSongName[i]
		song = load(songPath)
		songSeconds = song.get_length()
		$HSlider.max_value = int(songSeconds)
	return song


func _on_button_pressed():
	$AudioStreamPlayer.play()

func _on_btn_pause_pressed():
	if $AudioStreamPlayer.stream_paused == false:
		$AudioStreamPlayer.stream_paused = true
		$BtnPause.text = ">"
	else :
		$AudioStreamPlayer.stream_paused = false
		$BtnPause.text = "||"


func nextSong():
	if songCar <= listSongRoute.size():
		songCar += 1 
		if songCar> listSongRoute.size()-1: songCar = listSongRoute.size()-1
		$AudioStreamPlayer.stream = preloadSong(songCar)
		$AudioStreamPlayer.play()
		for i in  range(def):
			histogram.append(0)

func _on_btn_next_pressed():
	nextSong()

func dir_contents(path):
	var dir = DirAccess.open(path)
	if dir:
		dir.list_dir_begin()
		var file_name = dir.get_next()
		while file_name != "":
			if dir.current_is_dir():
				print("Found directory: " + file_name.get_base_dir())
			else:
				print("Found file: " + file_name)
				var ext = file_name.get_extension()
				if str(ext) == "mp3": 
					listSongRoute.append("res://music/"+file_name)
					listSongName.append(file_name)
			file_name = dir.get_next()
	else:
		print("An error occurred when trying to access the path.")

func anterior():
	if songCar >= 0:
		songCar += -1
		if songCar<0: songCar =0
		$AudioStreamPlayer.stream = preloadSong(songCar)
		$AudioStreamPlayer.play()

func _on_btn_ret_pressed():
	anterior()
	for i in  range(def):#initialize the histogram
		histogram.append(0)

@warning_ignore("unused_parameter")
func _process(delta):
	var freq = min_frec
	@warning_ignore("integer_division")
	var interval = (max_frec -min_frec) / def
	for i in range(def):
		var mag = spec.get_magnitude_for_frequency_range(freq, freq+interval)
		mag = linear_to_db(mag.length())
		histogram[i] = mag
		freq += interval
		queue_redraw()

func secTranform(time:int)->String:#Transformations for seconds and minutes
	var sec = time % 60
	@warning_ignore("integer_division", "shadowed_variable")
	var minute = (time / 60) % 60
	if sec >= 60:
		@warning_ignore("integer_division")
		minute += sec / 60
		sec %= 60
	return str(int(minute)).pad_zeros(2) + ":" + str(sec).pad_zeros(2)

func _draw():
	var sec_inSound = $AudioStreamPlayer.get_playback_position()
	$LblTime.text = secTranform(int(sec_inSound))
	if $AudioStreamPlayer.playing== true: $HSlider.value = sec_inSound
	var draw_pos = Vector2(0,0)
	@warning_ignore("integer_division")
	var w_interval = total_w / def
	if $AudioStreamPlayer.stream_paused == false:
		draw_line(Vector2(0, -total_h), Vector2(0, -total_h), Color.CRIMSON, 12.0,true)
		for i in range(def):
			if i> 4 and i<=14:
				draw_line(draw_pos, draw_pos+ Vector2(0, histogram[i]), Color.AQUA,12.0,true)
				draw_pos.x += w_interval
			elif  i>14:
				draw_line(draw_pos, draw_pos+ Vector2(0, histogram[i]), Color.DARK_BLUE,12.0,true)
				draw_pos.x += w_interval
			else :
				draw_line(draw_pos, draw_pos+ Vector2(0, histogram[i]), Color.DEEP_PINK,12.0,true)
				draw_pos.x += w_interval
	else:
		pass

func preloadSong(i):#load the songs
	var song
	var songSeconds
	if i <= listSongRoute.size()-1:
		var songPath = listSongRoute[i]
		$LblName.text = listSongName[i]
		song = load(songPath)
		songSeconds = song.get_length()
		$HSlider.max_value = int(songSeconds)
	return song


func _on_button_pressed():
	$AudioStreamPlayer.play()

func _on_btn_pause_pressed():
	if $AudioStreamPlayer.stream_paused == false:
		$AudioStreamPlayer.stream_paused = true
		$BtnPause.text = ">"
	else :
		$AudioStreamPlayer.stream_paused = false
		$BtnPause.text = "||"


func nextSong():
	if songCar <= listSongRoute.size():
		songCar += 1 
		if songCar> listSongRoute.size()-1: songCar = listSongRoute.size()-1
		$AudioStreamPlayer.stream = preloadSong(songCar)
		$AudioStreamPlayer.play()
		for i in  range(def):
			histogram.append(0)

func _on_btn_next_pressed():
	nextSong()

func dir_contents(path):
	var dir = DirAccess.open(path)
	if dir:
		dir.list_dir_begin()
		var file_name = dir.get_next()
		while file_name != "":
			if dir.current_is_dir():
				print("Found directory: " + file_name.get_base_dir())
			else:
				print("Found file: " + file_name)
				var ext = file_name.get_extension()
				if str(ext) == "mp3": 
					listSongRoute.append("res://music/"+file_name)
					listSongName.append(file_name)
			file_name = dir.get_next()
	else:
		print("An error occurred when trying to access the path.")

func anterior():
	if songCar >= 0:
		songCar += -1
		if songCar<0: songCar =0
		$AudioStreamPlayer.stream = preloadSong(songCar)
		$AudioStreamPlayer.play()

func _on_btn_ret_pressed():
	anterior()

I had to translate some comments :face_with_diagonal_mouth:
edit: I will upload the filedialog script separately so as not to confuse

1 Like

this is the filedialog’s script

extends Control

func _ready():
	get_tree().get_root().files_dropped.connect(_on_files_dropped)


func _on_button_pressed():
	$FileDialog.popup()

func _on_file_dialog_file_selected(path):
	print(path)
	OS.shell_open(path)
	
func _on_files_dropped(files):
	var path = files[0]
	print(path)
	OS.shell_open(path)
1 Like

You are using OS.shell_open this won’t open the file in your music player, it will try to open the file with your computer’s default music player. And the path might be wrong too, accepting anything with “res://” will fail sind your computer doesn’t know where “res://” is, only Godot knows.

ooh, so if that is the error then what is the solution?

You will have to actually load the file. Here’s a snippet from AudioStreamMP3’s docs

https://docs.godotengine.org/en/4.3/classes/class_audiostreammp3.html#class-audiostreammp3-property-data

1 Like

oh wow, but do I put that in the player script or the filedialog? The player, the interface with the filedialog is a scene that I made separate from the main one
......png

I do not know where it will reside, maybe on PlayLoad?

It will have to the connect FileDialog’s results to the AudioStreamPlayer. This function takes a path and produces a MP3 stream.

I tried to do it like this :dotted_line_face:
.........png

Cool, and you will have to use it too. Make sure to connect the file_selected signal to that function. It returns a value, which isn’t too useful at the moment, maybe emitting another signal from this script would be more helpful

Which sign of those two?
....png
edit: I connected it with the first one and it didn’t work :pensive:

What didn’t work?
Did you get an error? What did you change? How does the script look after connecting the signal and chanigng the return to a emit?

extends Control

func _ready():
	pass


func _on_button_pressed():
	$FileDialog.popup()

func _on_file_dialog_file_selected(path):
	load_mp3(path)



func load_mp3(path):
	var file = FileAccess.open(path, FileAccess.READ)
	var sound = AudioStreamMP3.new()
	sound.data = file.get_buffer(file.get_length())
	return sound

So the next steps for you are to take this returned value and plug it into an audio stream.

That’s why I recommended emitting a signal, so the loaded audio can go from this simple control node to your much more complicated Node2D script. For example on that Node2D script you have this function:

func anterior():
	if songCar >= 0:
		songCar += -1
		if songCar<0: songCar =0
		$AudioStreamPlayer.stream = preloadSong(songCar)
		$AudioStreamPlayer.play()

You would want something similar to this line, on that script, probably connected by a new signal.

$AudioStreamPlayer.stream = load_mp3(path)

On YouTube there is not a single video that talks about how to make an “in-game” music player, when I search for exactly that the only results are videos on how to add background music or sound effects :pensive: