Potential bug : AudioChannel.positionMs returning wrong value

Started by Monsieur OUXX, Tue 22/11/2016 13:33:56

Previous topic - Next topic

Monsieur OUXX

AGS 3.3.4

I've got this module that repeatedly loops a sound, starting from the middle of the sound :

Code: ags

AudioChannel* c;
void fooPlay(this AudioClip*)
{
  c = this.Play(1, eRepeat); //we play the sound on a first channel...
  if (c!=null) 
      c.Seek(c.LengthMs/2); //c.LengthMs is never 0; there's an actual sound

}


Then, in repeatedly_execute_always, I perform calculations based on the position.
Please note that I never change the position myself -- I never do .Seek apart from the first one, above. I use these calculations to adjust the volume.

Code: ags


function repeatedly_execute_always()
{
      //float pos = IntToFloat(c.PositionMs) / IntToFloat(c.LengthMs); //Just so you see what kind of calculations I'm doing
      
      if (c.PositionMs > c.LengthMs )
           Display("fPosMs=%f, fLenMs=%f", IntToFloat(c.PositionMs),  IntToFloat(c.LengthMs));
}


Surprisingly, I've come across situations where IntToFloat(c.LengthMs) = 13864.0, while IntToFloat(c.PositionMs) = 27597.0. This should be impossible.
It always happens at the precise moment when the sound reaches its very end (or its very beginning, since it's looping).
Even more surprisingly, this seems to happen randomly. It doesn't happen each time the sound loops; more like once every 4 or 5 loops.
This stinks like a bad float value rounding mishandling a 0.0 somewhere.

Because of the treatment I'm applying to the volume, this causes a sudden stutter. Could this be the cause of the famous "sound stuttering bug" in AGS?

Please note that I've performed a research on the forums to track this potential bug, but didn't find any reference to it.
If requested, I can provide the .MP3 file or full source code (I warn you, it's a massive beast -- But there's only one and only AudioChannel.Seek call in the whole code, I guarantee it).

 

Crimson Wizard

#1
I suspect that position is being advanced without testing if it's correct, and "repeatedly_execute_always" is called before engine actually realizes that song is done.
If you were at 3.3.5 or later I'd suggest trying to put your test code into "late_repeatedly_execute_always", which is called after game updates.
In other case, probably just adding safety check (as you did there) may help.

Although in any way this seems to be a bug, which needs to be fixed. I will check this out more carefully when I have time.


PS. Regarding the "stutter", we know what cause it for a long time, but it is solution that is not that easy. AGS updates all sound on the main thread, which means that it needs to poll (read audio stream) in skips between executing everything else. When there is a longer delay, like during room loading, or slow scripts, AGS cannot provide next audio chunk in time, and I think that previous one gets replayed by the sound library, or something like that (I am not 100% sure how that works internally).
Best, solution to this is to poll audio on dedicated thread. JJS did that earlier, but it is not perfect, and works more or less well only on Windows. That would require a pretty large refactoring of engine code to implement it properly. And even then, there is a big problem with synchronizing audio with game events: currently game developer can rely on audio following game ticks exactly, but with threaded audio we would need some kind of sync mechanism. Lipsync and videos with in-game audio overlay are the first to break when audio is played on separate thread.

Monsieur OUXX

Quote from: Crimson Wizard on Tue 22/11/2016 22:26:40
If you were at 3.3.5 or later I'd suggest trying to put your test code into "late_repeatedly_execute_always", which is called after game updates.
In other case, probably just adding safety check (as you did there) may help.
Although in any way this seems to be a bug, which needs to be fixed.

Thanks for the aknowledgement.
About the stuttering: forget my nonsense ;)
 

SMF spam blocked by CleanTalk