I've been learning how to use AudioStreamPlayer by creating different test projects. This one is a soundtrack player where you can go into another scene and play music. But for some reason it strikes me as poor coding because it looks like there are other better ways to go about it. The whole thing seems inefficient for some reason.

Here's the project folder:
https://workupload.com/file/EnxRmFabZef

Music Room scene:
`extends Control

func _ready() -> void:
pass

func _process(delta: float) -> void:
pass

func _on_play_button_pressed() -> void:
if GlobalAudioStreamPlayer.stream_track1.is_playing() == false:
GlobalAudioStreamPlayer.stream_track2.stop()
GlobalAudioStreamPlayer.stream_track3.stop()
GlobalAudioStreamPlayer.stream_track4.stop()
GlobalAudioStreamPlayer.stream_track5.stop()
GlobalAudioStreamPlayer.stream_track1.play()
elif GlobalAudioStreamPlayer.stream_track2.is_playing() == false:
GlobalAudioStreamPlayer.stream_track1.stop()
GlobalAudioStreamPlayer.stream_track3.stop()
GlobalAudioStreamPlayer.stream_track4.stop()
GlobalAudioStreamPlayer.stream_track5.stop()
GlobalAudioStreamPlayer.stream_track2.play()
elif GlobalAudioStreamPlayer.stream_track3.is_playing() == false:
GlobalAudioStreamPlayer.stream_track1.stop()
GlobalAudioStreamPlayer.stream_track2.stop()
GlobalAudioStreamPlayer.stream_track4.stop()
GlobalAudioStreamPlayer.stream_track5.stop()
GlobalAudioStreamPlayer.stream_track3.play()
elif GlobalAudioStreamPlayer.stream_track4.is_playing() == false:
GlobalAudioStreamPlayer.stream_track1.stop()
GlobalAudioStreamPlayer.stream_track2.stop()
GlobalAudioStreamPlayer.stream_track3.stop()
GlobalAudioStreamPlayer.stream_track5.stop()
GlobalAudioStreamPlayer.stream_track4.play()
elif GlobalAudioStreamPlayer.stream_track5.is_playing() == false:
GlobalAudioStreamPlayer.stream_track1.stop()
GlobalAudioStreamPlayer.stream_track2.stop()
GlobalAudioStreamPlayer.stream_track3.stop()
GlobalAudioStreamPlayer.stream_track4.stop()
GlobalAudioStreamPlayer.stream_track5.play()
pass

func _on_previous_button_pressed() -> void:
if GlobalAudioStreamPlayer.stream_track1.is_playing() == true:
GlobalAudioStreamPlayer.stream_track1.stop()
GlobalAudioStreamPlayer.stream_track5.play()
elif GlobalAudioStreamPlayer.stream_track2.is_playing() == true:
GlobalAudioStreamPlayer.stream_track2.stop()
GlobalAudioStreamPlayer.stream_track1.play()
elif GlobalAudioStreamPlayer.stream_track3.is_playing() == true:
GlobalAudioStreamPlayer.stream_track3.stop()
GlobalAudioStreamPlayer.stream_track2.play()
elif GlobalAudioStreamPlayer.stream_track4.is_playing() == true:
GlobalAudioStreamPlayer.stream_track4.stop()
GlobalAudioStreamPlayer.stream_track3.play()
elif GlobalAudioStreamPlayer.stream_track5.is_playing() == true:
GlobalAudioStreamPlayer.stream_track5.stop()
GlobalAudioStreamPlayer.stream_track4.play()
pass

func _on_next_button_pressed() -> void:
if GlobalAudioStreamPlayer.stream_track1.is_playing() == true:
GlobalAudioStreamPlayer.stream_track1.stop()
GlobalAudioStreamPlayer.stream_track2.play()
elif GlobalAudioStreamPlayer.stream_track2.is_playing() == true:
GlobalAudioStreamPlayer.stream_track2.stop()
GlobalAudioStreamPlayer.stream_track3.play()
elif GlobalAudioStreamPlayer.stream_track3.is_playing() == true:
GlobalAudioStreamPlayer.stream_track3.stop()
GlobalAudioStreamPlayer.stream_track4.play()
elif GlobalAudioStreamPlayer.stream_track4.is_playing() == true:
GlobalAudioStreamPlayer.stream_track4.stop()
GlobalAudioStreamPlayer.stream_track5.play()
elif GlobalAudioStreamPlayer.stream_track5.is_playing() == true:
GlobalAudioStreamPlayer.stream_track5.stop()
GlobalAudioStreamPlayer.stream_track1.play()
pass

func _on_stop_button_pressed() -> void:
GlobalAudioStreamPlayer.stream_track1.stop()
GlobalAudioStreamPlayer.stream_track2.stop()
GlobalAudioStreamPlayer.stream_track3.stop()
GlobalAudioStreamPlayer.stream_track4.stop()
GlobalAudioStreamPlayer.stream_track5.stop()
pass

func _on_shuffle_button_pressed() -> void:
GlobalAudioStreamPlayer.playlist_1.shuffle()
print(GlobalAudioStreamPlayer.playlist_1)
GlobalAudioStreamPlayer.playlist_1[1].stop()
GlobalAudioStreamPlayer.playlist_1[2].stop()
GlobalAudioStreamPlayer.playlist_1[3].stop()
GlobalAudioStreamPlayer.playlist_1[4].stop()
GlobalAudioStreamPlayer.playlist_1[0].play()
pass

func _on_return_button_pressed() -> void:
GlobalAudioStreamPlayer.stream_track1.stop()
GlobalAudioStreamPlayer.stream_track2.stop()
GlobalAudioStreamPlayer.stream_track3.stop()
GlobalAudioStreamPlayer.stream_track4.stop()
GlobalAudioStreamPlayer.stream_track5.stop()
get_tree().change_scene_to_file("res://assets/main_menu.tscn")
`

Audio Stream Player scene:
`extends Node

@onready var stream_track1 = $track1
@onready var stream_track2 = $track2
@onready var stream_track3 = $track3
@onready var stream_track4 = $track4
@onready var stream_track5 = $track5
@onready var stream_MM_bgm = $mm_bgm

@onready var playlist_1: Array = [stream_track1, stream_track2, stream_track3, stream_track4, stream_track5]
@onready var playlist_all: Array = [stream_track1, stream_track2, stream_track3, stream_track4, stream_track5, stream_MM_bgm]

func _ready():
pass
`

I like that you made an autoloaded scene out of your music player. The code can definitely be cleaned up and improved, and we can use the Array you have already created to do that without changing anything in the scene. I went ahead and modified your GDScript

MusicRoom.gd

extends Control

func _on_play_button_pressed() -> void:
	GlobalAudioStreamPlayer.play()

func _on_previous_button_pressed() -> void:
	GlobalAudioStreamPlayer.play_previous()

func _on_next_button_pressed() -> void:
	GlobalAudioStreamPlayer.play_next()

func _on_stop_button_pressed() -> void:
	GlobalAudioStreamPlayer.hard_stop()

func _on_shuffle_button_pressed() -> void:
	GlobalAudioStreamPlayer.play_shuffle()

func _on_return_button_pressed() -> void:
	GlobalAudioStreamPlayer.hard_stop()
	get_tree().change_scene_to_file("res://assets/main_menu.tscn")

BGMPlayer.gd

extends Node

@onready var stream_track1 = $track1
@onready var stream_track2 = $track2
@onready var stream_track3 = $track3
@onready var stream_track4 = $track4
@onready var stream_track5 = $track5
@onready var stream_MM_bgm = $mm_bgm

@onready var playlist_1: Array = [stream_track1, stream_track2, stream_track3, stream_track4, stream_track5]
@onready var playlist_all: Array = [stream_track1, stream_track2, stream_track3, stream_track4, stream_track5, stream_MM_bgm]

var current_track_index := 0
var _stopping_tracks_now := false

func _ready() -> void:
	for track in playlist_1:
		track.finished.connect(play_next)

func stop_all(except:int) -> void:
	_stopping_tracks_now = true
	for i in range(playlist_1.size()):
		if i != except and playlist_1[i].is_playing():
			playlist_1[i].stop()
	_stopping_tracks_now = false

func play() -> void:
	stop_all(current_track_index)
	current_track_index = clampi(current_track_index, 0, playlist_1.size() - 1)
	if not playlist_1[current_track_index].is_playing():
		playlist_1[current_track_index].play()

func hard_stop() -> void:
	stop_all(-1)
	current_track_index = 0

func play_next() -> void:
	if _stopping_tracks_now:
		return

	if current_track_index >= playlist_1.size() - 1:
		current_track_index = 0
	else:
		current_track_index = current_track_index + 1
	play()

func play_previous() -> void:
	if current_track_index <= 0:
		current_track_index = playlist_1.size() - 1
	else:
		current_track_index = current_track_index - 1
	play()

func play_shuffle() -> void:
	hard_stop()
	playlist_1.shuffle()
	print(playlist_1)
	play()

It makes sense for the BGMPlayer to do the actual playing, and for the music room to simply tell it that it needs to, so I've moved all of the music-playing code there.

Your functions had a lot of repeated code, and some code would never run the way you wanted it to. Your player also would not keep playing the next song after the current one ended, which is probably what we would expect a music player to do!

Instead of calling play and stop on each track individually, we use the playlist_1 array to stop and play them. We have a variable I named current_track_index. This tells us which player of the array we are currently on.

In our _ready function, we connect the players' finished signal to our play_next function. That way, when one track finishes playing, it will play the next one after it in the array.

In our stop_all function, we use a loop to stop every track if it is playing. We get an index i from the range function. Each loop, i will increase from 0 to the last element of our array. This way we stop every track without having to write stop() 5 or more times. If more tracks are added later, or tracks are removed, this loop will still work the same. We are passing an integer named except to stop_all. This is in case there is a particular track we want to keep playing. We check if our index is equal to except as well as if the indexed track in our array is playing before we decide to stop it.

Now in our play function, we call stop_all just in case for some reason another track is playing. We don't stop our current_track_index, and if it's already playing we don't need to play it again. You might decide you want to change this functionality to start from the top!

In hard_stop, we want every track to stop playing and our current track to move back to the beginning of the track list. Calling stop_all(-1) guarantees that no track will be allowed to keep playing.

In play_next and play_previous, we move our current_track_index up or down before calling play. This way, we don't have to write any more loops playing and stopping AudioSourcePlayers, but play will know which track we want to play now.

play_next has an additional check at the top. if _stopping_tracks_now, then we return out of the function and do nothing. This is because of the way AudioStreamPlayer.finished works. It will send a signal when it's done playing the AudioStream, but that includes when we call stop() on it. Because play_next() calls play() which calls stop_all() which calls stop(), we can see how this could potentially be bad. I've added _stopping_tracks_now as a safeguard against that.

and finally, all play_shuffle has to do is stop all the tracks, shuffle the array, and hit play again.

I hope that this example helps you see how you can use arrays and loops whenever you're dealing with a number of the same thing. Rather than writing code for every single item, you write one set of code that runs on every item.