Audiochannel throwing NPE (SOLVED)

Started by Laura Hunt, Sun 21/04/2019 21:44:16

Previous topic - Next topic

Laura Hunt

Hi all,

I'm running into an issue that's driving me crazy.

I've defined a global Audiochannel* pointer called "musicchannel". The "Music" type is set to just 1 channel max and no crossfade. I have the following code that gets triggered when the player hits "Start game" in my start menu:

Code: ags
musicchannel = aIntro.Play(eAudioPriorityNormal, eOnce);
musicchannel = aSoundtrack1.PlayQueued(eAudioPriorityNormal, eRepeat);


(Both aIntro and aSoundtrack1 are defined as type "Music")

This works perfectly, the intro plays once and then the actual soundtrack starts playing in a loop. However, when I get to a room where the music has to stop (using musicchannel.Stop() in the room_Load function), I get an NPE. But it doesn't make any sense because musicchannel is playing something!

However, if I don't use the intro and just play the main soundtrack directly (musicchannel = aSoundtrack1.Play(eAudioPriorityNormal, eRepeat)), then I don't get this issue. The music stops just as it should.

So the only difference between both scenarios is that I get the NPE only when I queue the second track after the intro. What is happening here then? When I queue a track it gets assigned a separate channel even though I've explicitely told AGS to play it in "musicchannel" and even though in theory there can only be 1 channel playing a "Music" file?

If this is the case, then I guess I can always use Game.StopAudio(Music) to stop the soundtrack, since I'm never going to have two music tracks playing simultaneously, but it bums me that AGS doesn't respect my channel assignment.

Any help would be greatly appreciated, as always!


Crimson Wizard

#1
PlayQueued returns null pointer if the clip cannot be played right away, because it does not know beforehand where it will be played (one could argue that having 1 reserved channel means there's little choice, but AGS does not make any assumptions). This means that your second script line will likely write null into musicchannel pointer.

Quote from: notarobotyet on Sun 21/04/2019 21:44:16When I queue a track it gets assigned a separate channel even though I've explicitely told AGS to play it in "musicchannel"

That's not what the script does, you cannot explicitly tell AGS to play on particular channel with these commands, but you store the channel pointer it decided to play on.
At the moment the only way to control what channels clip are going to be played on is through setting up reserved channels in the editor.

Laura Hunt

Quote from: Crimson Wizard on Sun 21/04/2019 21:52:22
PlayQueued returns null pointer if the clip cannot be played right away, meaning your second script line will write null into musicchannel pointer.

Hi CW, thanks as always for your answer! I'm not too sure what to make of this, however. Did I script this wrong, or is this simply the way AGS works and I just have to find ways around it? (such as the already mentioned Game.Stopaudio alternative?)

Crimson Wizard

#3
Quote from: notarobotyet on Sun 21/04/2019 21:58:24I'm not too sure what to make of this, however. Did I script this wrong, or is this simply the way AGS works and I just have to find ways around it? (such as the already mentioned Game.Stopaudio alternative?)

StopAudio is a good way if you like to stop all current clips of particular type for good. But it is not best if there's a chance that the necessary music is already playing.

Alternatively you may run through System.AudioChannels array in a loop and check PlayClip property for each to see if they play anything, and then test Type of the played clips, but that may be too much for what you are doing.

But, if you know for certain that there's only 1 music channel, and know its index, you may check it directly as System.AudioChannels[index] to see if it plays anything. If it's a clip that you like to keep playing, you let it stay, otherwise make it stop.

Laura Hunt

Quote from: Crimson Wizard on Sun 21/04/2019 22:02:04
StopAudio is a good way if you like to stop all current clips of particular type for good.

Alternatively you may run through System.AudioChannels array in a loop and check PlayClip property for each to see if they play anything, and then test Type of the played clips, but that may be too much for what you are doing.

Also, if you know for certain that there's only 1 music channel, and know its index, you may check it directly as System.AudioChannels[index] to see if it plays anything.

OK, between this and the edit to your previous answer I think I get a better picture of the way audio channels work. For now I'll stick to the StopAudio solution because I don't need anything more complicated, but it's good to know how I could handle other situations.

Thanks again!

Snarky

Quote from: Crimson Wizard on Sun 21/04/2019 22:02:04
But, if you know for certain that there's only 1 music channel, and know its index, you may check it directly as System.AudioChannels[index] to see if it plays anything. If it's a clip that you like to keep playing, you let it stay, otherwise make it stop.

If you know there's only one music channel (the MaxChannels of the Music AudioType is set to 1), you don't need to use the array. You can just assign your musicchannel variable the first time you play some music, and then never change it. Simply:

Code: ags
    musicchannel = aIntro.Play(eAudioPriorityNormal, eOnce);
    aSoundtrack1.PlayQueued(eAudioPriorityNormal, eRepeat);

Laura Hunt

Quote from: Snarky on Mon 22/04/2019 08:44:29

If you know there's only one music channel (the MaxChannels of the Music AudioType is set to 1), you don't need to use the array. You can just assign your musicchannel variable the first time you play some music, and then never change it. Simply:

Code: ags
    musicchannel = aIntro.Play(eAudioPriorityNormal, eOnce);
    aSoundtrack1.PlayQueued(eAudioPriorityNormal, eRepeat);


omg Snarky thank you!!! This is some amazing info! With this, the musicchannel.Stop() command now works perfectly, no more NPEs  ;-D

This does create an interesting issue if I happen to Ctrl+x directly to the room where the music stops while the intro is playing, because what it'll do in that case is cut the intro and skip to the next track in the queue. But this is never going to happen in-game, so... not really all that worrying.

Thanks again, man! I was just about to post again asking for more clarification on a couple of things, but this is exactly what I needed * happy dance *

Crimson Wizard

#7
Quote from: Snarky on Mon 22/04/2019 08:44:29
If you know there's only one music channel (the MaxChannels of the Music AudioType is set to 1), you don't need to use the array. You can just assign your musicchannel variable the first time you play some music, and then never change it. Simply:

Code: ags
    musicchannel = aIntro.Play(eAudioPriorityNormal, eOnce);
    aSoundtrack1.PlayQueued(eAudioPriorityNormal, eRepeat);


aIntro.Play may return null under some circumstances too (if sounds are disabled in config for example, see https://www.adventuregamestudio.co.uk/forums/index.php?topic=52176.0). Getting channel from System.AudioChannels array is the only method that guarantees non-null pointer ever. If you are able to calculate what the channel's id is you may as well save it at the game start.

SMF spam blocked by CleanTalk