Hi, I have a piece of code that checks the position a currently playing mp3 file is at.
AGS 3.4.0
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?
Are you positive that showObj(3) isn't called?
You could so some debugging:
else if(ambient.Position > 16300 && ambient.Position <= 16400)
{
showObj(3);
lblDebug.Text = String.Format("% sO3", lblDebug.Text);
}
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?
@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.
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.
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.
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
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
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.
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?
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:
function f(int a[])
{
}
and return array from function too:
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".
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:
function f(int a[])
{
}
and return array from function too:
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);
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.
You cannot pass non-managed array like that, only managed (dynamic) one:
int debugArray[];
function game_start()
{
debugArray = new int[300];
writeLog(debugArray);
}
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.