From alsa-devel-owner@alsa.jcu.cz  Thu Feb 18 00:10:23 1999
Received: from post.mail.nl.demon.net (post-10.mail.nl.demon.net [194.159.73.20])
	by marvin.jcu.cz (8.9.1a/8.9.1) with ESMTP id AAA11848
	for <alsa-devel@alsa.jcu.cz>; Thu, 18 Feb 1999 00:08:19 +0100
Received: from [212.238.75.184] (helo=obelix.vande-pol.demon.nl)
	by post.mail.nl.demon.net with esmtp (Exim 2.02 #1)
	id 10DG4e-0003JW-00; Wed, 17 Feb 1999 23:08:08 +0000
Received: (from frank@localhost)
	by obelix.vande-pol.demon.nl (8.8.7/8.8.7) id AAA03725;
	Thu, 18 Feb 1999 00:04:40 +0100
From: Frank van de Pol <frank@vande-pol.demon.nl>
Message-Id: <199902172304.AAA03725@obelix.vande-pol.demon.nl>
Subject: Re: More PCM/RT stuff (replies mostly)
To: alsa-devel@alsa.jcu.cz
Date: Thu, 18 Feb 1999 00:04:39 +0100 (MET)
Cc: data@havoc.gtf.org
In-Reply-To: <199902120251.VAA27164@havoc.gtf.org> from "Data" at Feb 11, 99 09:51:02 pm
Content-Type: text
Reply-To: alsa-devel@alsa.jcu.cz
Sender: alsa-devel-owner@alsa.jcu.cz
Precedence: list

Data wrote:
> 
> 
> Wow, looks like I maybe touched a nerve here! 

touching nerves is always a good thing when striving for perfection. Thanks
anyway for your wrap up / summary of this synchronisation issues. I'll
comment on some parts, throw in some new ideas, and at the same time recover
from the carnival :-) 


> 
> Anyway it should be quite 
> simple to call the sequencer timer callback from there. 

In the original prototype of the sequencer I implemented a generic timing
callback that would be called from 'any' clock source. The caller should
pass the period type (in ns) since previous invocation. Since period time is
known if the PCM fragment is used as timing source this would indeed be very
easy. However this snd_seq_timer_interrupt() function which can be found in
seq_timer.c has changed last few months, and now makes use of the ALSA tmr_
functions. Creating an ALSA timer that makes use of a PCM device would be
the way to go.


>   I'd originally thought to have the application set the fragment size,
> but I've got misgivings about this now.  I think it would make more sense 
> to not require applications to be concerned with the fragment size, as this
> depends on things like framerate etc.  Perhaps it would be better to let
> the sequencer do this, at least in situations where accurate clocking
> off the PCM driver is called for.  For example, a user might tell the
> sequencer to sync off of PCM, and generate MTC at a 25 fps framerate.
> This could be done through an ioctl.

This fragment size is definitely some that should not be dictated by the
sequencer but by the application that uses the PCM services. The fragment
size is application and hardware dependent. For example when doing hard disk
recording I'd prefer a larger fragment size (to prevent over/under-runs) then
when using the machine for real-time effects.

If I understood correctly it is possible to get an interrupt every fragment.
At 44.1kHz/16bit/stereo playback this would give us next frequencies
(freq=44100*2*2/fragsize)

	fragment	frequency
	--------	---------
	128 bytes	1378 Hz
	512		344 Hz
	1024		172 Hz
	4096		43 Hz

With this popular audio format we would have betting timing resolution that
the standard 100Hz clock on Intel platform when using a fragment size of
1024 or smaller. 

Jaroslav, how about this 'workaround' to overcome timer limitations on Intel
platform? Off subject: It might by the way also allow us to to get better
MIDI output on (SoundBlaster!) MIDI hardware that does not generate TX
interrupts.

If the sequencer is clocked from PCM timer these two audio sources are
always in sync, as the only master clock is the crystal clock of the codec:
audio and MIDI in sync for free.


> 
> -- JK: --
> We need add generic MTC/SMPTE support to sequencer code. Please,
> keep this in your mind. 

Indeed, and therefore the sequencer clock should be able to run asynchronous
from the timing source. To synchronise the sequencer to an external source
it would require adjusting the perceived period time for the sequencer -
just about the same as is done when synchronising the computer's date to an
NTP time server. This generic synchronisation is needed for both time (eg.
MTC, and possibly PCM playback/recording - depending on timer source used)
and song position (eg. midi clock) sources.


Data:
> but I've been under the impression, from reading Mr. van
> der Pol's proposal, that the intention was to leave that sort of thing
> to clients.  However, I do think it would make good sense in this case to

Please keep in mind that these sequencer clients can be interrupt driven
kernel code, and also be as standard included in the sequencer kernel.

> incorporate SMPTE into the sequencer itself.  At present the sequencer
> maintains two parallel timebases, which make use of the timer.c service
> (I suppose this often winds up using the system timer): one is straight
> sec/nsec time, the other bar/beat time with an associated resolution
> (ppq) and tempo (bpm).  

Correct. Purpose of these 2 timebases per sequencer is to allow both
synchronisation to/from real-time sources and bar/beat sources. In fact the
bar/beat time (ie. songposition) is derived from sec/nsec time.

> Now a SMPTE time is expressed as hours / minutes /
> seconds / frames / (optional) subframes; so to derive a SMPTE time from
> the current sec/nsec counter requires some division <shudder>.  Perhaps
> the sequencer could be altered to use a SMPTE-format counter internally,
> and generate SMPTE timestamps, so that no conversion would be necessary.
> Updating a SMPTE counter would require more time than updating the current
> time-counter, but probably far less than converting from that to SMPTE,
> an operation that would have to be done rather frequently.

<SHUDDER> Brrrrr, I very much dislike that idea. Using SMPTE time would be
very inefficient as we need to compare timestamps in many places (eg. in the
priority queues). A simple high resolution linear time format (like the
sec/nsec format) is really preferred for internal time stamps. No, using
SMPTE as internal format is a bad plan.

>   Furthermore, the audio and video worlds both run on SMPTE, and it works 
> very well.  I had concerns about timing when I first got into SMPTE sync - 

Great, so SMPTE is fine for external syncing your gear.


> -- JK: -- 
> There shouldn't be probably any timing messages in sequencer's
> queue.  I assume that timing messages will be delivered directly to
> sequencer devices when they'll arrive. 
> ---------
> 
> I think that if this turns out to be an issue, it will not be too
> difficult to deal with.  I can't remember, but perhaps there is an
> 'out-of-band' flag for events or the priority queue code automatically
> bumps up timing events.

Sort of, the out-of-band is an OSS way having a event handled immediately to
the dispatcher. In the ALSA sequencer you can set the event's flag to
SND_SEQ_PRIORITY_HIGH, to get it dispatched prior to already enqueued events
with a same timestamp.

>
> Again, I propose that the sequencer run _internally_ on SMPTE time.
Not accepted.

> The thing I would like to know is how best to change the sequencer's
> sync source; I suggest via ioctls, but there may be a way that better
> fits the sequencer's design.  If need be I will be happy to code these
> changes into the sequencer - they should not be especially difficult.

I did not have any plans for that. An ioctl() interface seems most obvious
to me, but perhaps the new ALSA ctl interface might be a good idea - I'm not
sure on that, as it seems to me that it is meant for device configuration.
Jaroslav, should application dynamicly fiddle with these ctl things?


> 
> 
> I have been considering an alternate approach to my original proposal
> which would require no change to the core sequencer at all.  One could
> construct a 'MTC generator' client.  This would register itself with the
> sequencer and wait for 'start' messages to come through.  Once they did
> it would begin polling the PCM driver and waiting for the sample queue
> tail to advance.  Based on the amount it advances, it would generate MTC.
> The client would be kernel-side (of course) and use the system timer to
> trigger polls.

I like the idea of using asynchronous applications for these timing critical
tasks instead of all being coupled. For each application the best trade-off
can be made. Instead of polling PCM driver I'd suggest to fetch time from
sequencer to make the MTC generator more generic. A disadvantage of using
sequencer time over PCM time would be that the sequencer time is only
updated periodically, and therefore it's granularity should be taken into
account.

>   I have done some calculation on the jitter inherent in this scheme, by 
> writing a sort of 'simulator'.  With a 44100 Hz sampling rate, 250 Hz polling 
....
>   These errors cannot be minimized until the polling rate reaches 
> approximately half a kilohertz, and become truly tolerable at one kilohertz.  
> As the system timer (HZ variable) on most Intel systems is only a hundred 
> hertz, we must conclude that some better algorithm is needed under these
> circumstances for generating reasonably accurate timecode.  (However,
> on Alphas the system would work very well, as the HZ value for those
> systems is usually 1024!)

Perhaps an other timing clock can be considered: the RTC (real-time clock)
which is standard available on Intel systems and is capable of (but almost
never used for) generating interrupts. Frequencies up to 8192 kHz should be
possible, with 1024Hz being default. See Documentation/rtc.txt in the Linux
sources for more information. This would also be a great candidate for the
sequencer timer.

>   In Mr. van de Pol's scenario, we would be relying fundamentally on the system 
> clock, and using sample position messages arriving from the PCM driver (albeit 
> at low frequency) to 'correct' this running clock, forcing it to correspond
> to the PCM driver's notion of time.  This, I think, would work well for
> many purposes, but not necessarily this one.  Timecode generators are
> expected to emit messages at very regular intervals.  MTC messages _must_
> go out every 8 1/3 mS, and from an embedded system or LTC-MTC converter
> this is an entirely reasonable requirement, and not at all difficult
> to fulfil.  If we could guarantee that the MTC routine would have the
> processor at exactly the 8 1/3 mS intervals required, Mr.  van de
> Pol's system would, I think, be quite satisfactory.  But we cannot
> guarantee this.  

For getting a really steady / low-jitter MTC clock like you'd get with those
embedded systems it seems that you need a real-time OS... Perhaps there is a
future for RT/Linux? Also consider getting some good interrupt source,
getting a 1ms resolution is hard to obtain with a 100Hz system clock :-(


>   My main concern, however, is that we in fact often require interrupts at 
> _half_-sample intervals.  For example, with a sampling rate of 44.1 KHz and a 
> frame rate of 30 fps, interrupts must occur every 367.5 samples.  Obviously 
> if we round off, using for example a 368-byte blocksize, we will quickly find
> ourselves out of sync with the playback signal.  The obvious solution to
> me would be to employ a variable blocksize, using for example alternating
> 367 and 368-sample blocks, or at least to have alternating _series_
> of these.  I do not know, without further study of the code, whether
> this would be practical.  Mr.  Kysela, have you any thoughts on this?

Just some question: how much jitter is tolerable for this MTC
synchronisation? It appears to me that you are worried about the error
introduced by rounding off by one audio sample (ie. max 11.3 us at 44.1kHz)
while the MIDI bytes are transmitted only at 31.25kb/s (32 us per bit). What
is the problem? Even the best hardware sync box can't get better than this
32 us. Are we chasing ghosts?

> - PBD -- 
> now, however, I'm also using the Pentium cycle counter to measure things
> more precisely, since it gives me (on a 450Mhz CPU) resolution down to
> about 20nanoseconds. Since I have a dual CPU machine, I am actually busy
> waiting for periods of less than 1 usec sometimes. 
> --------
> 
> Hmm.  Could the Pentium cycle counter be, perhaps, employed as a system
> timer by timer.c, for example?  Having 20 nS resolution sounds almost
> luxurious to me :)

If this cycle counter can't generate interrupts and thus be used as a clock
it won't do any good for synchronisation or sequencer purposes. It can only
be used to get an (super) accurate timeofday, which is not relevant if we
are syncing to an external source (eg. audio playback)


> Thanks very much for everybody's insightful comments, and let's do keep
> this thing going so we can wind up with CODE!  (which you'll see coming
> from me regardless, I'm afraid! :) )


Is there any reason why we should be afraid of your code ? :-) 

Regards,
Frank.

+---- --- -- -  -   -    - 
|Frank van de Pol                  -o)
|Frank@vande-pol.demon.nl          /\\
|                                 _\_v
|Linux - Why use Windows, since there is a door?
|
|ALSA Sequencer: http://www.vande-pol.demon.nl/alsa/

