SDL perfect Timing help

Hi.

Im trying to create a metronome with SDL and im having some problems because there is always a little delay with the timmer, and as it has to be perfect (because it is a metronome) i would like to know how can i get PERFECT timings.

heres my loop right now:

Code:
while (quit==0)
{
apply_surface(bg, screen,0,0);

    if (SDL_PollEvent(&event))
    {

        //Quit Metronome
        if (event.type==SDL_QUIT)
        {
            quit=1;
        }
        //--------------------------------

        if (event.type==SDL_KEYDOWN)
        {
            SDL_EnableUNICODE(SDL_ENABLE);

            if (event.key.keysym.unicode>=(Uint16)'0' && event.key.keysym.unicode <=(Uint16)'9')
            {
                if (x<11)
                {
                time_str[x]=(char)event.key.keysym.unicode;
                x++;
                text=NULL;
                }
            }

            if (event.key.keysym.sym==SDLK_RETURN)
            {
                x=0;
                while (x<11)
                {
                time_str[x]=' ';
                x++;
                }
                x=0;
                text=NULL;
            }


        }
        text=TTF_RenderText_Solid(font, time_str, textcolor);

    }

    y=atoi(time_str);
    if (y<=0) y=1;

    if ((SDL_GetTicks()-timing) >= (60000/y))
    {
        Mix_PlayChannel(-1,clap,0);
        timing=SDL_GetTicks();
    }

    apply_surface(text, screen,0,0);

    SDL_Flip(screen);
}

Help pls

Hi,

First of all, instead of your :

if ((SDL_GetTicks()-timing) >= (60000/y))
{
Mix_PlayChannel(-1,clap,0);
timing=SDL_GetTicks();
}

You might want to try something more like:

const Uint32 length = (60000/y);
if ((SDL_GetTicks()-timing) >= length)
{
Mix_PlayChannel(-1,clap,0);
timing += length;
}

That way, your timing doesn’t drift, meaning that if your first beat
took (length+1) ms, and your second beat took (length+2) ms, you’ll get
a drift. With the second way of doing it, if one beat is slightly
longer, the next one will be slightly shorter so that overall, you
respect the target BPM.

Hope this helped,

Martin

ShiroAisu wrote:> Hi.

Im trying to create a metronome with SDL and im having some problems
because there is always a little delay with the timmer, and as it has
to be perfect (because it is a metronome) i would like to know how can
i get PERFECT timings.

heres my loop right now:

Code:

while (quit==0)
{
    apply_surface(bg, screen,0,0);

    if (SDL_PollEvent(&event))
    {

        //Quit Metronome
        if (event.type==SDL_QUIT)
        {
            quit=1;
        }
        //--------------------------------

        if (event.type==SDL_KEYDOWN)
        {
            SDL_EnableUNICODE(SDL_ENABLE);

            if (event.key.keysym.unicode>=(Uint16)'0' && 

event.key.keysym.unicode <=(Uint16)‘9’)
{
if (x<11)
{
time_str[x]=(char)event.key.keysym.unicode;
x++;
text=NULL;
}
}

            if (event.key.keysym.sym==SDLK_RETURN)
            {
                x=0;
                while (x<11)
                {
                time_str[x]=' ';
                x++;
                }
                x=0;
                text=NULL;
            }


        }
        text=TTF_RenderText_Solid(font, time_str, textcolor);

    }

    y=atoi(time_str);
    if (y<=0) y=1;

    if ((SDL_GetTicks()-timing) >= (60000/y))
    {
        Mix_PlayChannel(-1,clap,0);
        timing=SDL_GetTicks();
    }

    apply_surface(text, screen,0,0);

    SDL_Flip(screen);
}

Help pls


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

hmm correct me if im wrong but if i set “length” as a constant its value cannot be changed during the program right?? because i want to be able to change it, is there any problem if i declare it as a variable???

That might not be the best way, but you can keep going with it by moving
this into your SDLK_RETURN test:
y=atoi(time_str);
if (y<=0) y=1;

And add this there too:
length = (60000/y);

Remove the const of course.

Jonny DOn Tue, Jun 15, 2010 at 11:04 AM, ShiroAisu wrote:

hmm correct me if im wrong but if i set “length” as a constant its value
cannot be changed during the program right?? because i want to be able to
change it, is there any problem if i declare it as a variable???


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

I guess

Leonardo

I guess Martin point is that you are doing a division operation
(60000/y) and accessing the clock two times, each frame. Each is
somewhat costly and your timer may drift because of it.

2010/6/15 ShiroAisu :> hmm correct me if im wrong but if i set “length” as a constant its value

cannot be changed during the program right?? because i want to be able to
change it, is there any problem if i declare it as a variable???


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Yes, my point was that setting the “timing” variable to SDL_GetTicks()
instead of increasing it of the interval length would cause a drift.

That being said, I don’t think there’s anything wrong with the "const"
in front of the length variable: if “y” changes, length will change as
well. It’s const in the scope of the block it’s declared in, meaning
that the value it has can’t be changed after it’s first assigned, but
every time your function is called, it will have the good value.

Add a “static” in front of it though, and then it would keep only the
first value it’s assigned…

Martin

Leonardo Guilherme wrote:> I guess

Leonardo

I guess Martin point is that you are doing a division operation
(60000/y) and accessing the clock two times, each frame. Each is
somewhat costly and your timer may drift because of it.

2010/6/15 ShiroAisu :

hmm correct me if im wrong but if i set “length” as a constant its value
cannot be changed during the program right?? because i want to be able to
change it, is there any problem if i declare it as a variable???


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Ok, i have this now, but it still has the delay :\

Code:

    y=atoi(time_str);
    if (y<=0) y=1;
    const Uint32 length=(60000/y);

    if ((SDL_GetTicks()-timing) >= length)
    {
        Mix_PlayChannel(-1,clap,0);
        timing += length;
    }

    apply_surface(text, screen,0,0);
    SDL_Flip(screen);

Ok, i have this now, but it still has the delay :\

Have you considered using Mix_PlayChannel’s looping feature? That is,
use:

    Mix_PlayChannel(-1,clap,-1);

The downside of this idea is that you’ll need to alter your wavefile
at runtime to have the correct length. But if you manage that, I
suspect that the timing will be much more reliable.

Alternately, you could use Mix_HookMusic to supply your own player.
You could then use a single wavefile by just padding it out with as
much silence as you need each time the hook function is called. (The
hook function would also allow you to synchronize the changes to the
screen with the repetitions, probably via SDL_PushEvent.)

b

i was trying to avoid sound loops with Mix_PlayChannel function, because the time between the sounds changes lots of times and it could get weird

i was trying to avoid sound loops with Mix_PlayChannel function,
because the time between the sounds changes lots of times and it
could get weird

Sounds like using a hook function to control playback is really the
way to go.

b

Precisely what kind of delay are you seeing? Delayed display of your text? Depending on LCD monitor brands and models you may get a significant delay in the display of images (nothing to do with SDL).

Delayed sound? Software mixing systems inevitably have some latency, often significant, you want to go as close to the hardware as you can to maintain synchronization between image and sound (this is
why music programs use different techniques on each platform to minimize latency).

Any advice I can give on sound synchronization will be platform-specific (for example on Windows you want to request an exclusive DirectSound context rather than a cooperative one, on Linux you want
to make sure you choose hw:0,0 or similar as your alsa device).

P.S. I would like to know if there is an effort to offer a “minimal latency” sound option in SDL that may be less compatible but significantly reduces latency (for example, skipping pulseaudio on
Linux and going directly to ALSA), as long as it can gracefully fail the request I’m sure some people will find it useful for music programs…On 06/15/2010 02:31 PM, ShiroAisu wrote:

Ok, i have this now, but it still has the delay :\

Code:

    y=atoi(time_str);
    if (y<=0) y=1;
    const Uint32 length=(60000/y);

    if ((SDL_GetTicks()-timing) >= length)
    {
        Mix_PlayChannel(-1,clap,0);
        timing += length;
    }

    apply_surface(text, screen,0,0);
    SDL_Flip(screen);

SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


LordHavoc
Author of DarkPlaces Quake1 engine - http://icculus.org/twilight/darkplaces
Co-designer of Nexuiz - http://alientrap.org/nexuiz
"War does not prove who is right, it proves who is left." - Unknown
"Any sufficiently advanced technology is indistinguishable from a rigged demo." - James Klass
"A game is a series of interesting choices." - Sid Meier

The delay is not a sound nor an image delay, the delay in in the order to play the sound (but the sound plays right when it should)

the problem is that im playing the sound when the corrent time - timing is >= to 60000/y, now imagine that y=100. that would mean that when the corrent time - timing >= 60000/100 it would play the sound. but the problem is that i want it exacly when corrent time-timing == 60000/100 but that never happens because there are other orders behind and when the program gets to this part it has passed some more ms’s (but never exacly 60000/100)

so im looking for a way to round and solve this problem.

Btw can u explain a little bit about that hook function pls??

Btw can u explain a little bit about that hook function pls??

Check out the documentation for Mix_HookMusic(). Mix_HookMusic() lets
you set up a callback function that is responsible for supplying that
actual bytes that get sent to the soundcard. So you just need to
define a callback that plays back your wavefile, followed by however
many bytes of silence you need to take you to the time for the next
repetition (after which it feeds bytes from the sample again, and so
on ad infinitum). I’ve written code like this before, and as far as I
can tell it’s the only really reliable way to control the timing of a
playback loop with SDL_mixer.

b

the only problem with this is that i wanted a way to solve this only working with the timing itself, because Mix_HookMusic() works but if i want to make for example an image blink constantly i cant use that, so i really wanted to know how to get a perfect timing

inst there a way of for example, i have a code and when SDL_GetTicks - timing = 6000 (6 seconds) it would jump to a specific line of the code?? or something like that??

You cannot guarantee that timing precision this way because if, for
example, your loop take 3ms to run, and you have GetTicks - timing =
5999, next iteration it will be 6002. A thing that you can do is setup
another thread, make it sleep for a selected delay and then make it
play your sound. I don’t know how to actually code this, is just an
idea… if i’m not getting you wrong.

Leonardo

2010/6/17 ShiroAisu :> the only problem with this is that i wanted a way to solve this only working

with the timing itself, because Mix_HookMusic() works but if i want to make
for example an image blink constantly i cant use that, so i really wanted to
know how to get a perfect timing

inst there a way of for example, i have a code and when SDL_GetTicks -
timing = 6000 (6 seconds) it would jump to a specific line of the code?? or
something like that??


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Is the SDL timer API more precise? You could probably do it all through
that.
http://www.libsdl.org/cgi/docwiki.cgi/SDL_AddTimer

Jonny DOn Thu, Jun 17, 2010 at 7:16 PM, Leonardo Guilherme < leonardo.guilherme at gmail.com> wrote:

You cannot guarantee that timing precision this way because if, for
example, your loop take 3ms to run, and you have GetTicks - timing =
5999, next iteration it will be 6002. A thing that you can do is setup
another thread, make it sleep for a selected delay and then make it
play your sound. I don’t know how to actually code this, is just an
idea… if i’m not getting you wrong.

Leonardo

2010/6/17 ShiroAisu :

the only problem with this is that i wanted a way to solve this only
working
with the timing itself, because Mix_HookMusic() works but if i want to
make
for example an image blink constantly i cant use that, so i really wanted
to
know how to get a perfect timing

inst there a way of for example, i have a code and when SDL_GetTicks -
timing = 6000 (6 seconds) it would jump to a specific line of the code??
or
something like that??


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

As suggested, a callback timer is going to be way more accurate. The best
accuracy, though, will be creating your own thread and adding a delay. The
reason your own thread will be better is because I believe SDL_SetTimer runs
through a background event system, which has the potential to be a
millisecond or two off (reason is: I tried this method to stabilize a
physics simulation, and found I had to do some correction to the timing,
which wasn’t always exact).

Take care,
-AlexOn Fri, Jun 18, 2010 at 8:00 AM, Jonathan Dearborn wrote:

Is the SDL timer API more precise? You could probably do it all through
that.
http://www.libsdl.org/cgi/docwiki.cgi/SDL_AddTimer

Jonny D

On Thu, Jun 17, 2010 at 7:16 PM, Leonardo Guilherme < leonardo.guilherme at gmail.com> wrote:

You cannot guarantee that timing precision this way because if, for
example, your loop take 3ms to run, and you have GetTicks - timing =
5999, next iteration it will be 6002. A thing that you can do is setup
another thread, make it sleep for a selected delay and then make it
play your sound. I don’t know how to actually code this, is just an
idea… if i’m not getting you wrong.

Leonardo

2010/6/17 ShiroAisu :

the only problem with this is that i wanted a way to solve this only
working
with the timing itself, because Mix_HookMusic() works but if i want to
make
for example an image blink constantly i cant use that, so i really
wanted to
know how to get a perfect timing

inst there a way of for example, i have a code and when SDL_GetTicks -
timing = 6000 (6 seconds) it would jump to a specific line of the code??
or
something like that??


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org