Is the AGS frame rate inconsistent?

Started by LameNick, Sat 04/02/2017 11:17:53

Previous topic - Next topic

LameNick

Hi, I have a piece of code that checks the position a currently playing mp3 file is at.

AGS 3.4.0
Code: ags

function room_RepExec()
{
  
  if(ambient){
    if(ambient.Position > 15900 && ambient.Position <= 16100 ) 
    {
      showObj(0);
    }
    else if(ambient.Position > 16100 && ambient.Position <= 16200)
    {
      showObj(1);
    }
    else if(ambient.Position > 16200 && ambient.Position <= 16300)
    {
      showObj(2);
    }
    else if(ambient.Position > 16300 && ambient.Position <= 16400)
    {
      showObj(3);
    }
    else if(ambient.Position > 16400 && ambient.Position <= 16500)
    {
      showObj(4);
    }
  }
}


It seems that all the code gets subsequently executed except code contained in the one before the last ‘else if' statement. When I give bigger span between the positions in the condition, it works.
So far it appears as if no game cycles happen within that particular 100 ms timespan and there should be 4 given that there are 40 game cycles per second.
I tried using ‘rep.._execute_always' but doesn't help. When I play a different mp3 file, again some of the ‘if/else if' statements get executed and some don't.

Is the time rate of game cycles unreliable?
Is there a way to check audio channel position accurately?
How much wood would a wood chuck chuck if a wood chuck could chuck wood?

Khris

Are you positive that showObj(3) isn't called?
You could so some debugging:
Code: ags
    else if(ambient.Position > 16300 && ambient.Position <= 16400)
    {
      showObj(3);
      lblDebug.Text = String.Format("% sO3", lblDebug.Text);
    }

dayowlron

Could it also be due to windows itself stealing some time slices. What else do you have running that would slow down the computer itself and not just the program?
Pro is the opposite of Con                       Kids of today are so much different
This fact can clearly be seen,                  Don't you know?
If progress means to move forward         Just ask them where they are from
Then what does congress mean?             And they tell you where you can go.  --Nipsey Russell

LameNick

@Khris: Yup, it doesn't call anything within that statement. As i mentioned, if the gap between the audio track positions in the condition is wider e.g. 400ms the code does get executed.
Also with different mp3s, different lines in the code won't get validated as true, but at the same time it always stays consistent with that particular mp3 file.

@dayowlron: My computer doesn't seem slower in any way. All that is running now is AGS and Opera.   
How much wood would a wood chuck chuck if a wood chuck could chuck wood?

Crimson Wizard

#4
The thing is that by default the music is updated on the main thread in AGS, which means audio position is literally bound to game progress. The only way to break that synchronization is to enabled threaded audio, by manually putting "threaded=1" in the game config file (there is no visual option in winsetup for now, because the feature is still experimental).


EDIT:
Quote from: LameNick on Sat 04/02/2017 13:34:14
@Khris: Yup, it doesn't call anything within that statement. As i mentioned, if the gap between the audio track positions in the condition is wider e.g. 400ms the code does get executed.
I'd try to log out audio position somewhere each tick to see which steps it takes.

LameNick

Thanks CW for your advice! Enabling threaded audio solved the issue, although the showObj function that displays an object every time an audio channel position is detected, executes with such a delay that it's usability is questionable.

Quote from: Crimson Wizard on Sat 04/02/2017 14:20:36
Quote from: LameNick on Sat 04/02/2017 13:34:14
@Khris: Yup, it doesn't call anything within that statement. As i mentioned, if the gap between the audio track positions in the condition is wider e.g. 400ms the code does get executed.
I'd try to log out audio position somewhere each tick to see which steps it takes.

If you mean exporting debug info, that's one of the areas of AGS I still haven't learned.
But I'll try to find a way to see how many audio channel positions the RepExec function  gets to check within those few hundred ms.
How much wood would a wood chuck chuck if a wood chuck could chuck wood?

LameNick

So I exported the audioChannel positions that were checked between 16200 and 16500 ms and the array contains 12 results  which means the timing of the game cycles seems to be correct but they consist of only 4 different numbers that are repeated, which is weird.
Spoiler

   
16271
   
16271
   
16271
   
16343
   
16343
   
16416
   
16416
   
16416
   
16416
   
16488
   
16488
[close]

And when compiled and played with threaded audio it shows twice as many results:
Spoiler
   16271    16271    16271    16271    16343    16343    16416    16416    16416    16416    16488    16488    16271    16271    16271    16271    16343    16343    16416    16416    16416    16416    16488    16488
[close]


I have to say i am quite confused about how this works.
Btw. I tried to use File.WriteInt function to write the integer values without turning them to string but they got converted into some different characters.

Code: ags
function writeLog()
{
  File *log = File.Open("$SAVEGAMEDIR$/log.txt", eFileAppend);
  for(int a=0; a < i; a++)
  {
    log.WriteString (String.Format("%d", debugArray[a]));
  }
  log.Close();
}


function room_RepExec()
{
  if(ambient)
  {
    if(ambient.Position > 16200 && ambient.Position <= 16500 ) 
    {
      debugArray[i] = ambient.Position;
      i++;
    }
    else if (ambient.Position > 16500 && finishedCount == false)
    {
      finishedCount = true;
      writeLog();
    }
  }
}




Also I'd like to ask, is it possible to pass array as an argument?



How much wood would a wood chuck chuck if a wood chuck could chuck wood?

Crimson Wizard

#7
This might need further investigation, but I have a feeling that position that channel returns does not refer to actual playback position, but to the beginning of some chunk that was loaded up into internal player.

Quote from: LameNick on Sun 05/02/2017 23:09:26
Btw. I tried to use File.WriteInt function to write the integer values without turning them to string but they got converted into some different characters.
WriteInt writes integers in their binary format, not as human-readable text, so coverting to formatted strings is a proper way to do this. (Also AFAIK WriteInt adds extra safeguard bytes around value).

Quote from: LameNick on Sun 05/02/2017 23:09:26
Also I'd like to ask, is it possible to pass array as an argument?

Yes:
Code: ags

function f(int a[])
{
}

and return array from function too:
Code: ags

int[] f2()
{
    int a[] = new int[10];
    return a;
}

Sadly there is no way to get array's length from array, so you need to deal with that somehow too... When passing as argument it is simple to add another argument for array size, but when returning array some workaround is required, like the last element containing value that means "end of array".

LameNick

Quote from: Crimson Wizard on Sun 05/02/2017 23:31:22
This might need further investigation, but I have a feeling that position that channel returns does not refer to actual playback position, but to the beginning of some chunk that was loaded up into internal player.

I guess its got to be something like that, because the audio plays without a problem.


Quote from: Crimson Wizard on Sun 05/02/2017 23:31:22
Yes:
Code: ags

function f(int a[])
{
}

and return array from function too:
Code: ags

int[] f2()
{
    int a[] = new int[10];
    return a;
}

Sadly there is no way to get array's length from array, so you need to deal with that somehow too... When passing as argument it is simple to add another argument for array size, but when returning array some workaround is required, like the last element containing value that means "end of array".

Thanks CW for explanation, but I'm afraid its not enough to surpass my stupidity. No matter what I try, passing the array as an argument doesn't work:
Quoteroom3.asc(138): Error (line 138): Type mismatch: cannot convert 'int*' to 'int[]'

Spoiler

int debugArray[300];

function writeLog(int logsArray[]){}

writeLog(debugArray);
[close]

I also tried to put the length of the static array as declared into the brackets in the argument, and bunch of other syntaxes,but nothing helps. I'm not sure what am i doing wrong.





How much wood would a wood chuck chuck if a wood chuck could chuck wood?

Crimson Wizard

You cannot pass non-managed array like that, only managed (dynamic) one:

Code: ags

int debugArray[];

function game_start()
{
    debugArray = new int[300];
    writeLog(debugArray);
}

LameNick

Thanks! I was somewhat reluctant to use dynamic array as I didn't understand when, where and why it's size needs to be declared at all, it somehow doesn't align with my (virtually non-existent) knowledge of programing, or perhaps my stupid preconceptions about programing. But now I finally got it to work.
How much wood would a wood chuck chuck if a wood chuck could chuck wood?

SMF spam blocked by CleanTalk