I have made a global soundtrack object to handle music and a function to swap tracks even time the player stops. I have a problem though. On testing by itself, the player works so far so good. But when I try to put it as an autoload and use it, I keep getting "Node not found (when direct referencing child)" and "null instances (if onready var referencing them)". Pretty sure this is a loading issues. My tracks are compressed down to OGG and are only loaded when they are queued to play and yet, this is happening whenever I try to actually insert it into my game. I have not found a lot of decent tutorials outside of "here's how to play a sound."

Here's the code - any best practices or optimization advice is appreciated as I am just learning the AudioStreamPlayer.

extends Node2D


onready var _calm = $Calm
onready var _pursuit = $Pursuit
onready var _hidden = $Hidden
onready var _escape = $Escape
onready var _scene = $Event

var _calmTrack = 0
var _chaseTrack = 0


const _calmTracks = [
	"res://music/calm/Attic_Springs.ogg",
	"res://music/calm/NoHome.ogg",
	"res://music/calm/Seeking.ogg",
	"res://music/calm/VoidSoul.ogg",
	"res://music/calm/Wave.ogg"
]

const _pursuitLoops = [
	"res://music/tense/hurt_loop1.ogg",
	"res://music/tense/mono_loop2.ogg",
	"res://music/tense/noesc_loop3.ogg",
	"res://music/tense/reven_loop1.ogg",
	"res://music/tense/run_loop.ogg"
]

const _hiddenLoops = [
	"res://music/tense/hurt_loop2.ogg",
	"res://music/tense/mono_loop1.ogg",
	"res://music/tense/noesc_loop1.ogg",
	"res://music/tense/reven_loop2.ogg",
	"res://music/tense/run_loop2.ogg",
]

const _escapeShots = [
	"res://music/tense/hurt_end.ogg",
	"res://music/tense/mono_end.ogg",
	"res://music/tense/noesc_end.ogg",
	"res://music/tense/reven_end.ogg",
	"res://music/tense/run_end.ogg"
]

const _sceneBGM = [
	"res://music/calm/Doors.ogg",
	"res://music/calm/Vessel.ogg",
	"res://music/tense/springs_end.ogg"
]


## randomize numbers for song pulls, connect end shots back to regular music
func _ready():
	var _out_ = $Timer.connect("timeout",self,"_initialize")
	$Timer.start(5)

func _initialize():
	_shuffle_bgm()
	
	if Director._inPursuit == true:
		_pursuit_music()
	else:
		_calm_music()


### play calm music
func _calm_music():
	var _myCalm = load(_calmTracks[_calmTrack])
	$Calm.stream = _myCalm
	$Calm.play()
	
	if Director._inPursuit:
		$Calm.stop()
		_pursuit_music()

	if Director._inPursuit == false and $Calm.playing == false:
		_shuffle_bgm()
		_calm_music()

## play tense music
func _pursuit_music():
	var _myChase = load(_pursuitLoops[_chaseTrack])
	$Pursuit.stream = _myChase
	$Pursuit.play()
	
	if Director._playerIsHidden == true:
		$Pursuit.stop()
		_hidden_music()


## play suspense music
func _hidden_music():
	var _myHidden = load(_hiddenLoops[_chaseTrack])
	$Hidden.stream = _myHidden
	$Hidden.play()
	
	if Director._inPursuit == false:
		$Hidden.stop()
		_escape_music()


## play escape one-shot
func _escape_music():
	var _myEsc = load(_escapeShots[_chaseTrack])
	$Escape.stream = _myEsc
	$Escape.play()
	
	if $Escape.playing == false:
		_shuffle_bgm()
		_calm_music()

## rng function to change song pull
func _shuffle_bgm():
	randomize()
	_calmTrack = randi() % 4
	_chaseTrack = randi() % 4
  • The code looks okay. Probably an issue with your node setup. Make sure that the autoload script is on the root of that particular scene. If it is on another node, it might initialize in the wrong order. You might also want to double check the names of the nodes. I find using get_node() works better (it compiles to the same code, but it's more clear in text). For example:

    onready var _calm = get_node("Calm")

    You want to always use onready and load all node path references at the top. So use the code I just posted, and then search through your script and replace all occurrences of $Calm with _calm and for the rest of the variables too. It seems you are doing both ways in the code you posted, so that may be the issue.

The code looks okay. Probably an issue with your node setup. Make sure that the autoload script is on the root of that particular scene. If it is on another node, it might initialize in the wrong order. You might also want to double check the names of the nodes. I find using get_node() works better (it compiles to the same code, but it's more clear in text). For example:

onready var _calm = get_node("Calm")

You want to always use onready and load all node path references at the top. So use the code I just posted, and then search through your script and replace all occurrences of $Calm with _calm and for the rest of the variables too. It seems you are doing both ways in the code you posted, so that may be the issue.

    cybereality oh yes, i was trying different methods and got frustrated, may have forgot to clean that up. I did your method and got this:

    E 0:00:00.598 get_node: (Node not found: "Calm" (relative to "/root/AudioManager").)
    <C++ Error> Condition "!node" is true. Returned: nullptr
    <C++ Source> scene/main/node.cpp:1325 @ get_node()
    <Stack Trace> AudioManager.gd:7 @ _ready()

    I am not sure why this is happening.
    My debugger is showing, no matter what method i use, that the players are coming up null. The tracks seem to be loading fine. (IN FACT I have some errors where the music plays and then the program seems to crash.)

    That means the node Calm is not a child of AudioManager. When you hit Play, look on the upper left and click Remote, so you can see how the scene tree looks and which objects are there. It's hard to say how to fix it without knowing your node setup.

      cybereality Hmmm... curious. It's not happening when it is NOT an autoload. I am wondering if maybe load order is suspect here. What's your best practice when using audio at autoload? I am wondering if I have should have these commands call from a separate global object.

      The autoload needs to be a completely self contained scene (for example a node2d with children saved as a tscn file). It can access other elements, but it will work better if it is totally independent.

        cybereality Yeah I had it like that but - i figured it out. I did an autoload on the node and NOT the script and it seems to be working great now. I guess loading the script caused errors? The functions I made are also seemingly working now!

        The script can be attached to the root node inside the autoload scene and they will load together. Note that scripts can be on a scene and also inside the scene (or both) and you can't really tell in the UI.