AudioChannel Won't Switch to New Clip

Started by MaeveGlaistig, Wed 19/12/2018 23:40:57

Previous topic - Next topic

MaeveGlaistig

I am 1000% sure I'm just missing something really simple somewhere, but since I've done everything I can think of, I'm here to ask for help from all you pros.  :)

I have an AudioChannel for background music that is checked in the room_Load of every room; if it's playing the correct music for that room, then the channel continues doing its thing, but if it's not, it should switch to the correct track.  The code for each room looks like this:

Code: ags
if ((BGMusic == null) || (BGMusic.PlayingClip != aStreets))
  {
    BGMusic = aStreets.Play();
  }
  else if (BGMusic.PlayingClip == aStreets)
  {
    return;
  }


The problem is that with the code above, when the player enters the room, the clip from the previous room continues to play in BGMusic and the new room's clip (in this example, aStreets) does not replace it.  There are no errors on save or run.

I have BGMusic set as a global variable audiochannel and have confirmed that all clips are loaded into AGS.  Music, Sound, and AmbientSound are all set to 0 (unlimited) maximum channels, but I have also tried it with 1 and 8 channels; the same problem occurs when it's on 8 channels, while if it's just 1 channel, the previous music stops but the new track isn't played.  I thought maybe both tracks were playing simultaneously somehow, but all tracks are at the same volume and it doesn't seem like this is the case.

What am I missing?

Khris

#1
The simplest explanation is that you have pasted the room_Load function into the rooms without linking it in the room's event pane, which means the code never gets called in the first place.

Here's my solution: http://www.adventuregamestudio.co.uk/forums/index.php?topic=50363.msg636486911#msg636486911

For reference, here's all you need:

Code: ags
// global script
AudioChannel *bgm;

void SetBGM(AudioClip *music) {
  if (bgm == null || bgm.PlayingClip != music) bgm = music.Play();
}

// add to existing on_event, if applicable 
void on_event(EventType event, int data) {
  if (event == eEventEnterRoomBeforeFadein) {
    if (data >= 3 && data <= 9) SetBMG(aOcean);
    if (data >= 10 && data <= 14) SetBGM(aCave);
    // etc.
  }
}

MaeveGlaistig

Sadly that's not the case, but it's always good to go back and check, so thank you.  :)  Room_Load is linked in all rooms.

Thanks, Khris!  I had actually seen that bit of code through trawling the forums for information, but wasn't entirely sure how to use it.  I think I have a better idea on it now!

...but unfortunately, the same problem is still happening.  If I set the max music channels to 0 or any number 2-8, just the first room's track plays, and in the next room keeps on playing while the new room's track does not replace it.  When confining music channels to 1, the first room's track plays, then stops when the second room is entered but without anything replacing it (silence).

Based on your code, I now have the following in my GlobalScript:

Code: AGS
  void SetBGM(AudioClip *music) 
  {
    if (BGMusic == null || BGMusic.PlayingClip != music) 
    {
      BGMusic = music.Play();
    }
  }


And then:

Code: AGS
void on_event(EventType event, int data)
{
  if (event == eEventEnterRoomBeforeFadein) 
  {
    if ((player.Room == 1) || (player.Room == 2) || (player.Room == 3) || (player.Room == 9) || (player.Room == 14)) SetBGM(aMarysTheme);
    if ((player.Room == 48) || (player.Room == 49) || (player.Room == 50) || (player.Room == 56) || (player.Room == 63)) SetBGM(aMirrorMaze);
    if ((player.Room == 38) || (player.Room == 39) || (player.Room == 40) || (player.Room == 45) || (player.Room == 47)) SetBGM(aHauntedHouse);
    if ((player.Room == 28) || (player.Room == 29) || (player.Room == 30) || (player.Room == 33) || (player.Room == 36)) SetBGM(aMenagerie);
    if ((player.Room == 21) || (player.Room == 22) || (player.Room == 25) || (player.Room == 26) || (player.Room == 27)) SetBGM(aMuseum);
    if ((player.Room == 37) || (player.Room == 69) || (player.Room == 65)) SetBGM(aFortuneTeller);
    if ((player.Room == 11) || (player.Room == 12) || (player.Room == 13)) SetBGM(aStreets);
    if ((player.Room == 19) || (player.Room == 20)) SetBGM(aAfterHoursTent);
    if ((player.Room == 17) || (player.Room == 18)) SetBGM(aCircus);
    if ((player.Room == 71) || (player.Room == 72)) SetBGM(aIntroScreen);
    if (player.Room == 66) SetBGM(aGarden);
    if (player.Room == 67) SetBGM(aDeath);
    if (player.Room == 16) SetBGM(aVardo);
    if (player.Room == 70) SetBGM(aIntroScreen);
  }
}


Any idea why this would happen?  The code seems correct, which keeps making me think it must be an issue with a setting in the Audio tab somewhere.

morganw

Do the AudioClips for the music have their type set to music, either directly or by their folder?

Snarky

Are you able to get the clip to play at all, in any way? Maybe it's just broken somehow...

Crimson Wizard

Setting music channels to 1 seems like a way to go in your case since you want music clips to automatically replace each other (otherwise you'd have to script this).

QuoteWhen confining music channels to 1, the first room's track plays, then stops when the second room is entered but without anything replacing it (silence).

Hmm, perhaps check that all those clips actually belong to music type as morganw suggested above, and also that they have same priority. Or try passing higher priority as an argument to Play in SetBGM.

MaeveGlaistig

Double-checked, but all clips are set to "music" and appear in the Music folder:



They are also all set to inherit priority, which unless I call something different should keep any one of them from overriding the others.

The clips do play, both separately outside of AGS and within it - previously, in my kludgy code I was calling when entering each room, they played fine under a basic MusicName.Play();.  I've only had this problem since trying to switch to using an AudioChannel formally to get them to properly swap when entering different rooms.  (Yeah, I know, I'm using AudioChannels either way since they're a constant, but before I was just using the Play command and letting AGS do it on its own instead of actively working with it!)

I do have voice acting and sound effects in the game, but they shouldn't be interfering (they're also all properly set to Sound, I checked) since I haven't actually gotten to the part where any of them would be called - this issue happens immediately on walking from room to room, whether interacting with other things or not.

Per CW's advice, I tried adding a High Priority tag to calling SetBGM, like so:

Code: AGS
void SetBGM(AudioClip *music) 
  {
    if (BGMusic == null || BGMusic.PlayingClip != music) 
    {
      BGMusic = music.Play(eAudioPriorityHigh, eRepeat);
    }
  }


But no dice, the same result.

MaeveGlaistig

Well, hey, I got it.  I had Music set to crossfade:



Set it back to "no" and voila, all the clips now play.  Is that a known thing that causes problems or am I just not using it right?

Now, of course, the clips are playing... so I can tell that the behavior still isn't working quite right, because it just restarts the clip in each room instead of checking to see if it's already playing and taking no action if it is.  So close.  Any ideas there?

Khris

Yeah, cross-fading needs two channels.

Quote from: MaeveGlaistig on Thu 20/12/2018 14:00:22because it just restarts the clip in each room instead of checking to see if it's already playing

That is exactly the problem my code is supposed to solve. Where did you declare
Code: ags
AudioChannel *bgm;
?
Because if you did that in the header, you need to move it to the script. (declaring variables in the header creates separate ones for each room; since the variable is thus always null when you enter a room, the check never works as intended)

MaeveGlaistig

Ah, so if I understand right, you need two channels to crossfade a track, but I can't have two channels with what I'm trying to do because then AGS will just play the second track on the second channel instead of crossfading them together on the same one?

Hmm, I didn't declare the channel because I had it as a global variable AudioChannel, which I thought would work as well!

I removed the global channel and replaced it by declaring it in the GlobalScript, like so:

Code: AGS
AudioChannel *BGMusic;

//Set SetBGM Background Music behavior
void SetBGM(AudioClip *music) 
  {
    if (BGMusic == null || BGMusic.PlayingClip != music) 
    {
      BGMusic = music.Play();
    }
  }


and

Code: AGS
void on_event(EventType event, int data)
{
  if (event == eEventEnterRoomBeforeFadein) 
  {
    if ((player.Room == 1) || (player.Room == 2) || (player.Room == 3) || (player.Room == 4) || (player.Room == 5) || (player.Room == 6) || (player.Room == 7) || (player.Room == 8) || (player.Room == 9) || (player.Room == 14) || (player.Room == 15) || (player.Room == 10) || (player.Room == 64) || (player.Room == 68)) SetBGM(aMarysTheme);
    if ((player.Room == 48) || (player.Room == 49) || (player.Room == 50) || (player.Room == 51) || (player.Room == 52) || (player.Room == 53) || (player.Room == 54) || (player.Room == 55) || (player.Room == 56) || (player.Room == 57) || (player.Room == 58) || (player.Room == 59) || (player.Room == 60) || (player.Room == 61) || (player.Room == 62) || (player.Room == 63)) SetBGM(aMirrorMaze);
    if ((player.Room == 38) || (player.Room == 39) || (player.Room == 40) || (player.Room == 41) || (player.Room == 42) || (player.Room == 43) || (player.Room == 44) || (player.Room == 45) || (player.Room == 46) || (player.Room == 47)) SetBGM(aHauntedHouse);
    if ((player.Room == 28) || (player.Room == 29) || (player.Room == 30) || (player.Room == 31) || (player.Room == 32) || (player.Room == 33) || (player.Room == 34) || (player.Room == 35) || (player.Room == 36)) SetBGM(aMenagerie);
    if ((player.Room == 21) || (player.Room == 22) || (player.Room == 23) || (player.Room == 24) || (player.Room == 25) || (player.Room == 26) || (player.Room == 27)) SetBGM(aMuseum);
    if ((player.Room == 37) || (player.Room == 69) || (player.Room == 65)) SetBGM(aFortuneTeller);
    if ((player.Room == 11) || (player.Room == 12) || (player.Room == 13)) SetBGM(aStreets);
    if ((player.Room == 19) || (player.Room == 20)) SetBGM(aAfterHoursTent);
    if ((player.Room == 17) || (player.Room == 18)) SetBGM(aCircus);
    if ((player.Room == 71) || (player.Room == 72)) SetBGM(aIntroScreen);
    if (player.Room == 66) SetBGM(aGarden);
    if (player.Room == 67) SetBGM(aDeath);
    if (player.Room == 16) SetBGM(aVardo);
    if (player.Room == 70) SetBGM(aIntroScreen);
  }
}


...but no change, with the same restarting of the clip in every room.  Does the placement of the code in GlobalScript (for example, before/after game_start) matter?

Snarky

#10
Unless there have been any changes recently, AGS uses an internal, otherwise inaccessible Audio Channel (which I think shows up as index -1 in some places) to do the built-in crossfading, so that shouldn't be a problem in itself.

It's time to do some debugging, by editing the SetBMG() function to Display what's actually happening (the value of BGMusic and BGMusic.PlayingClip, compared to music). You can see an example of how you can display all the available info here, but you probably need something much less elaborate.

Oh, also, you can make those conditions a lot shorter, you know:

Code: ags
    if ((player.Room >= 1 && player.Room <= 10) || player.Room >= 14 || player.Room == 15 || player.Room == 64 || player.Room == 68) SetBGM(aMarysTheme);
    if (player.Room >= 48 && player.Room <= 63) SetBGM(aMirrorMaze);
    if (player.Room >= 38 && player.Room <= 47) SetBGM(aHauntedHouse);
    if (player.Room >= 28 && player.Room <= 36) SetBGM(aMenagerie);
    if (player.Room >= 21 && player.Room <= 27) SetBGM(aMuseum);

MaeveGlaistig

Thank you - I was meaning to simplify it but wanted to figure out what was going on before I messed with it too much more.  :)

Using your debugging code, I see that when the game starts, channel 1 (BGMusic) plays the first track (aIntroScreen)... but when moving to the next room, all channels show that nothing is playing, even though the next room's clip (aStreets) clearly is.  Which explains why it keeps restarting in every room, I guess, since it's apparently playing in the background somehow rather than on channel 1 (BGMusic) the way it's supposed to.  I tried taking an action that triggered a sound effect and was able to confirm that that appeared on channel 2 as expected.

This is with music channels set to a maximum of 1; out of curiosity, I tried setting it to 0 (no maximum) to see what difference that would make, which predictably resulted in the first clip continuing to play on channel 1.  The other tracks started playing simultaneously when entering other rooms, which is also expected since they'd just start in another channel... except that they also didn't show as playing on any of the audiochannels in the debugging GUI, which continued to just show channel 1 playing the first clip and all other channels as empty.

I think it's possible I may have borked something in the debugging GUI display itself since I'm not sure what this would mean otherwise, so I'm going to mess with it some more.  In the meantime, I have a workaround with a big ugly eEventEnterRoomBeforeFadein set of conditions to check which room the player is in and which room they came from, which will work if I don't figure out how to do it in a cleaner/simpler way.

Thanks for all your help, folks!  I'll come back if/when I figure it out to post for posterity.  :)

SMF spam blocked by CleanTalk