Adventure Game Studio

AGS Support => Beginners' Technical Questions => Topic started by: cat on Sun 16/12/2018 18:42:15

Title: [SOLVED] Playing an AudioClip blocking?
Post by: cat on Sun 16/12/2018 18:42:15
Is it possible to play an audio clip in a blocking manner (i.e. synchronously)? It is part of a sound related puzzle where after a certain interaction I play a sound and when the sound is finished I do something else.

If it is not possible, I guess I could either check in repEx for the playback to finish or do a while loop in the calling function and check there.
Ideally, I would be able to combine this with a cutscene i.e. player interacts with item, sound starts, player clicks or presses escape, the action afterwards is performed immediately.
Title: Re: Playing an AudioClip blocking?
Post by: ManicMatt on Sun 16/12/2018 20:55:47
If I understand that correctly, use the Wait(); command to block all actions after playing the sound. You might need a bit of trial and error to get the right timing when entering the number in the brackets. That's what I have been doing anyway, so I don't know if there is a better way. Sometimes I needed a character to animate and have him making say, a picking up sound, so I wouldn't use a blocking animation, instead I'd have the animation start as eNoBlock, then Wait, then play the sound, then Wait again, using the correct time I need to have the animation fully play out.
Title: Re: Playing an AudioClip blocking?
Post by: cat on Mon 17/12/2018 15:00:09
Good point. Wait() should also work well with cutscenes.
Title: Re: Playing an AudioClip blocking?
Post by: Snarky on Mon 17/12/2018 15:49:59
I believe this will work?

Code (ags) Select
void PlayBlocking(this AudioClip*, AudioPriority pri)
{
  AudioChannel* c = this.Play(pri, eOnce);
  while(c.PlayingClip == this) Wait(1);
}
Title: Re: Playing an AudioClip blocking?
Post by: cat on Mon 17/12/2018 19:18:38
I think so, but probably not within a cutscene. AFAIK wait() will be skipped in a cutscene, but this loop can't be stopped.
Title: Re: Playing an AudioClip blocking?
Post by: Crimson Wizard on Mon 17/12/2018 19:34:19
Quote from: cat on Mon 17/12/2018 19:18:38
I think so, but probably not within a cutscene. AFAIK wait() will be skipped in a cutscene, but this loop can't be stopped.

You may try:
Code (ags) Select

while(c.PlayingClip == this)
{
    Wait(1);
    if (Game.SkippingCutscene)
        c.Stop();
}


Also you need to check if Play returned null, which it also will in case cutscene skip started earlier, I think.
Title: Re: Playing an AudioClip blocking?
Post by: cat on Mon 17/12/2018 19:40:33
Interesting, thanks!
Title: Re: Playing an AudioClip blocking?
Post by: morganw on Mon 17/12/2018 19:48:00
If looking for a more generic solution, I think you should be careful of blocking against an AudioChannel without any checks on it (it might get something else played on it unless you are sure nothing else could hijack it with a high priority, or just use it directly). Depending on the format and how you want to handle playback stopping early, it might be safer to read the duration immediately after playback starts (incorporating a null check for people who have the audio turned off) and then block against the duration instead of the actual playback.
Title: Re: Playing an AudioClip blocking?
Post by: cat on Mon 17/12/2018 20:29:36
Also very interesting! Though, I checked the documentation of AudioChannel.LengthMs:
"This is supported by all file types, but with MIDI music it is only accurate to the nearest second."

I am playing rather short MIDI files, so this will not be accurate enough. Maybe I'll have some time later to convert them to ogg, but I'm working to a deadline with MAGS.
Title: Re: Playing an AudioClip blocking?
Post by: Snarky on Mon 17/12/2018 22:05:53
Quote from: morganw on Mon 17/12/2018 19:48:00
If looking for a more generic solution, I think you should be careful of blocking against an AudioChannel without any checks on it (it might get something else played on it unless you are sure nothing else could hijack it with a high priority, or just use it directly). Depending on the format and how you want to handle playback stopping early, it might be safer to read the duration immediately after playback starts (incorporating a null check for people who have the audio turned off) and then block against the duration instead of the actual playback.

Since we're checking whether it's playing that particular clip, I don't see how those things would be a concern. The only case would be if the clip is interrupted by another copy of the same clip, which seems like the kind of edge case where you should just say "don't do that".
Title: Re: Playing an AudioClip blocking?
Post by: morganw on Mon 17/12/2018 23:51:29
Depends what you are syncing the audio with, I mean that the loop can potentially end early as well as never end.
I did preface this with "generic solution" (for people searching for how to implement this in their game) because this has edge cases, as well as a missing null check on the channel.
Title: Re: Playing an AudioClip blocking?
Post by: Snarky on Tue 18/12/2018 18:18:40
There should be a null check, you're right, but otherwise I think the other edge cases are "works as designed". If the point is to block for as long as that clip is playing, then exiting early if the clip is interrupted is correct, and not exiting for as long as the clip plays is arguably correct.

The right solution here really does depend on the specific requirements, though. The fact that turning off or failing to initialize sound will bypass the blocking entirely may very well not be desired behavior in many situations. If you want to block deterministically for a specific duration that matches the normal duration of the clip exactly (even for MIDI clips), there's no way to do that other than manually syncing a Wait() with the clip length, AFAIK.
Title: Re: Playing an AudioClip blocking?
Post by: ManicMatt on Thu 20/12/2018 20:19:52
Quote from: Snarky on Tue 18/12/2018 18:18:40
..there's no way to do that other than manually syncing a Wait() with the clip length, AFAIK.

Its like we came full circle to my first post! :)
Title: Re: Playing an AudioClip blocking?
Post by: cat on Sun 23/12/2018 11:00:52
So, for posterity, this is what I'm using and it works great, also regarding cutscenes:

Code (ags) Select

void PlayBlocking(this AudioClip*, AudioPriority prio)
{
   AudioChannel* c = this.Play(prio, eOnce);

   if (c)
   {
      while(c.PlayingClip == this)
      {
          Wait(1);
          if (Game.SkippingCutscene)
          {
              c.Stop();
          }
      }
   }
}


Thanks, guys!