On Wednesday 12 May 2004 3:29 pm, John Anderson wrote:
> >If that's all OK, next thing is I should be able to make a small
> > test program that checks the ALSA queue times against JACK
> > without having the rest of Rosegarden running.
>
> I'm going on holiday from Friday, so I probably won't get much time
> to look at it tomorrow. Assuming that a small program will take you
> longer than the rest of today ;-)

No, it's attached.  Build this  with -ljack -lasound, then when you 
run it it should print out once per second how accurate the sequencer 
queue appears to be when compared against the system clock and JACK 
frame count.  Example:

The most interesting figure is the last one (jq diff), which is the 
difference between JACK frame count and queue timer.  You can expect 
this to vary anywhere up to the JACK period size because of the lack 
of accuracy in being woken up from sleep to take the measurement, but 
if it's any more than that, then I'd like to know about it.  Well, 
I'd like to know if it isn't too.

Give it a good few minutes to run, if you can, watching for 3- or 
4-digit frame counts in that last bottom-right figure.

Thanks!

(btw I'm also committing this in CVS in base/test/seq/, subject to the 
usual anon CVS delay.)


Chris
#include <alsa/asoundlib.h>
#include <alsa/seq.h>
#include <jack/jack.h>
#include <sys/time.h>

static jack_nframes_t sample_frames = 0;

void normalize(struct timeval *tv)
{
    if (tv->tv_sec == 0) {
	while (tv->tv_usec <= -1000000) { tv->tv_usec += 1000000; --tv->tv_sec; }
	while (tv->tv_usec >=  1000000) { tv->tv_usec -= 1000000; ++tv->tv_sec; }
    } else if (tv->tv_sec < 0) {
	while (tv->tv_usec <= -1000000) { tv->tv_usec += 1000000; --tv->tv_sec; }
	while (tv->tv_usec > 0) { tv->tv_usec -= 1000000; ++tv->tv_sec; }
    } else { 
	while (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; ++tv->tv_sec; }
	while (tv->tv_usec < 0) { tv->tv_usec += 1000000; --tv->tv_sec; }
    }
}

int
jack_process(jack_nframes_t nframes, void *arg)
{
    sample_frames += nframes;
}

jack_nframes_t
rt_to_frame(struct timeval tv, jack_nframes_t sample_rate)
{
    if (tv.tv_sec < 0) tv.tv_sec = -tv.tv_sec;
    if (tv.tv_usec < 0) tv.tv_usec = -tv.tv_usec;
    return
	tv.tv_sec * sample_rate +
	((tv.tv_usec / 1000) * sample_rate) / 1000 +
	((tv.tv_usec - 1000 * (tv.tv_usec / 1000)) * sample_rate) / 1000000;
}

int
main(int argc, char **argv)
{
    snd_seq_t *handle;
    int portid;
    int npfd;
    struct pollfd *pfd;
    int queue;
    int i;
    int rval;
    struct timeval starttv;
    int countdown = -1;
    snd_seq_queue_timer_t *timer;
    snd_timer_id_t *timerid;
    jack_client_t *jclient;
    jack_nframes_t sample_rate;
    
    if ((jclient = jack_client_new("queue-timer-jack")) == 0) {
	fprintf(stderr, "failed to connect to JACK server\n");
	return 1;
    }

    jack_set_process_callback(jclient, jack_process, 0);

    sample_rate = jack_get_sample_rate(jclient);

    if (snd_seq_open(&handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0) {
	fprintf(stderr, "failed to open ALSA sequencer interface\n");
	return 1;
    }

    snd_seq_set_client_name(handle, "generator");

    if ((portid = snd_seq_create_simple_port
	 (handle, "generator",
	  SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ, 0)) < 0) {
	fprintf(stderr, "failed to create ALSA sequencer port\n");
	return 1;
    }

    if ((queue = snd_seq_alloc_queue(handle)) < 0) {
	fprintf(stderr, "failed to create ALSA sequencer queue\n");
	return 1;
    }

    snd_seq_queue_timer_alloca(&timer);
    snd_seq_get_queue_timer(handle, queue, timer);
    snd_timer_id_alloca(&timerid);
    snd_timer_id_set_class(timerid, SND_TIMER_CLASS_PCM);
    snd_timer_id_set_sclass(timerid, SND_TIMER_SCLASS_NONE);
    snd_timer_id_set_card(timerid, 0);
    snd_timer_id_set_device(timerid, 0);
    snd_timer_id_set_subdevice(timerid, 0);
    snd_seq_queue_timer_set_id(timer, timerid);
    snd_seq_set_queue_timer(handle, queue, timer);

    if (jack_activate(jclient)) {
        fprintf (stderr, "cannot activate jack client");
        exit(1);
    }

    snd_seq_start_queue(handle, queue, 0);
    snd_seq_drain_output(handle);

    gettimeofday(&starttv, 0);

    while (countdown != 0) {

	snd_seq_queue_status_t *status;
	const snd_seq_real_time_t *rtime;
	struct timeval tv, qtv, jtv, diff, jdiff;
	jack_nframes_t frames_now;

	snd_seq_queue_status_alloca(&status);

	snd_seq_get_queue_status(handle, queue, status);
	rtime = snd_seq_queue_status_get_real_time(status);

	gettimeofday(&tv, 0);

	frames_now = sample_frames;
	fprintf(stderr, "    frames: %ld\n", frames_now);

	qtv.tv_sec = rtime->tv_sec;
	qtv.tv_usec = rtime->tv_nsec / 1000;

	tv.tv_sec -= starttv.tv_sec;
	tv.tv_usec -= starttv.tv_usec;
	normalize(&tv);

	jtv.tv_sec = frames_now / sample_rate;
	frames_now -= jtv.tv_sec * sample_rate;
	jtv.tv_usec = (int)(((float)frames_now * 1000000) / sample_rate);

	diff.tv_sec = tv.tv_sec - qtv.tv_sec;
	diff.tv_usec = tv.tv_usec - qtv.tv_usec;
	normalize(&diff);

	jdiff.tv_sec = jtv.tv_sec - qtv.tv_sec;
	jdiff.tv_usec = jtv.tv_usec - qtv.tv_usec;
	normalize(&jdiff);

	fprintf(stderr, " real time: %12ld sec %8ld usec /%12ld frames\nqueue time: %12ld sec %8ld usec /%12ld frames\n jack time: %12ld sec %8ld usec /%12ld frames\n   rq diff: %12ld sec %8ld usec /%12ld frames\n   jq diff: %12ld sec %8ld usec /%12ld frames\n",
		tv.tv_sec, tv.tv_usec, rt_to_frame(tv, sample_rate),
		qtv.tv_sec, qtv.tv_usec, rt_to_frame(qtv, sample_rate),
		jtv.tv_sec, jtv.tv_usec, rt_to_frame(jtv, sample_rate),
		diff.tv_sec, diff.tv_usec, rt_to_frame(diff, sample_rate),
		jdiff.tv_sec, jdiff.tv_usec, rt_to_frame(jdiff, sample_rate));

	fprintf(stderr, "\n");
	struct timespec ts;
	ts.tv_sec = 1;
	ts.tv_nsec = 0;
	nanosleep(&ts, 0);
    }
}

Reply via email to