Re: [linux-audio-dev] Sequencer Sync Woes

New Message Reply About this list Date view Thread view Subject view Author view Other groups

Subject: Re: [linux-audio-dev] Sequencer Sync Woes
From: Paul Davis (pbd_AT_Op.Net)
Date: Wed Feb 07 2001 - 00:27:05 EET


> But if I'm sending 24ppq sync pulses, at 140bpm, this means I need to
>send a sync tick every 4.5ms. For 16th notes (a typical bassline or
>snare roll or whatever), this means every 6.7ms. How can you not
>notice if your resolution > 10ms?

i'll rephrase :) find me someone who is generating MIDI sync (i would
call them "clock") pulses on Linux ...

> I find it interesting that you bothered to seperate it out into cases.
>You really want to avoid doing that float divide?

No, its just that way so that I could grok what the hell was going on :)

> This code seems to be
>equivalent:

Well, there is a key comment:

                /* every timer signal corresponds to at least one
                   tick. Found out how much time has elapsed, and
                   figure out just how many ticks have gone by. But
                   note that the elapsed time might not be greater
                   than usecs_per_tick, so we have to allow some slop
                   here.
                */

i don't understand how that could be, but apparently, something was
making me believe that it was happening. as a result, i had to finesse
things a little. its possible that i just wasn't understanding what
was going on.

you're also not carrying usecs over from each computation. i found
that the "error" could accumulate fairly quickly. if you set
usecs_per_tick to, say, 1000, and there is jitter of, say, 25usecs,
then after just 40 runs through the computation, you may have missed
an entire extra clock tick. granted, you wouldn't *expect* the jitter
to all go in one direction, and so it should cancel out. but in fact,
the jitter *does* tend to be biased toward the thread executing this
code a bit "late". as a result, i was careful to keep track of any
"left over" usecs from each computation.

its quite possible that i got a lot of this wrong though. i don't have
a very good head for this stuff - my skills tend to be more in system
design and architecture, and i frequently miss the obvious with this
kind of code.

--p

> struct timeval tcurrent_tick;
> struct timezone tz;
> unsigned long current_usecs;
> unsigned long elapsed_usecs;
> int inc;
>
> gettimeofday (&tcurrent_tick, &tz);
>
> current_usecs = (tcurrent_tick.tv_sec * 1000000) + tcurrent_tick.tv_use
>c;
> elapsed_usecs = carry_usecs + (current_usecs - last_tick_usecs);
>
> inc = (int) ((double) elapsed_usecs / (double) usecs_per_tick);
>
> if (inc > 0) {
> midi_ticks += inc;
> last_tick_usecs = current_usecs;
> carry_usecs = elapsed_usecs - (inc * usecs_per_tick);
> carry_usecs = carry_usecs > 0 ? carry_usecs : 0;
> }
>
> My code doesn't bother with the divide, I simply have the code to do
>the next notes in a loop like this:
>
> struct timeval tv, tvdiff, result;
> int diff;
>
> gettimeofday( &tv, 0 );
> diff = (tv.tv_sec - last_sec) * 1000 * 1000 + tv.tv_usec - last_usec;
>
> if( diff > usecs_per_tick ) {
> while( diff > usecs_per_tick ) {
> diff -= tt;
> ++midiclockcounter;
>
> // Handle current tick, send out notes,
> // whatever.
> }
>
> tvdiff.tv_sec = 0;
> tvdiff.tv_usec = diff;
>
> // result = tv - tvdiff;
> diffTimes( &result, &tv, &tvdiff );
>
> last_sec = result.tv_sec;
> last_usec = result.tv_usec;
> }
>
> I should probably do like you did and just keep around the usecs,
>instead of always converting everything to struct timeval format.
>
>--
>Billy Biggs bbiggs_AT_dumbterm.net
>http://www.billybiggs.com/ wbiggs_AT_uwaterloo.ca
>


New Message Reply About this list Date view Thread view Subject view Author view Other groups

This archive was generated by hypermail 2b28 : Wed Feb 07 2001 - 01:09:42 EET