=========================================================================
                             RealTime.library
=========================================================================

Introduction
~~~~~~~~~~~~
    RealTime library is a shared library for the Amiga, designed to help
applications synchronize to one another. An example of this is an animation
player which could synchronize to a music program; Or, both of them could
be sync'd to an external source such as SMPTE time code.
    RealTime allows any number of timing contexts, or "conductors", so
called because of their similarity to the conductor of an orchestra.
RealTime's function is essentially to function as a metronome or master
clock, distributing a continuous stream of timing information to different
tasks.

Goals
~~~~~
    The goals of RealTime are:

    1. To encourage development of music software and synchronized
multimedia applications by providing a working driver to the public.

    2. To spur the development of applications which allow the user to
create and control multimedia presentations.

Operating System Requirements
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    The RealTime library functions identically under 2.0 or 1.3. However,
many of the various utilities that come with RealTime require GadTools or
other 2.0 features.

The Conductor System
~~~~~~~~~~~~~~~~~~~~
    RealTime maintains a list of conductors and sends timing information to
individual "players" (like the musicians in an orchestra). There can be any
number of conductors, and each represents a seperate timing context, just
like real musicians playing in different concert halls don't have to stay
in time with each other. Similarly, there can be any number of players.
    An application will usually create a single PlayerInfo structure
(using the CreatePlayer() call) and the attach it to a conductor. (If the
conductor does not yet exist, it will automatically be created). In some
cases, an application might want to create more than one player, when
multiple independent timing contexts are required.
    The conductors are driven by a central clock in RealTime called the
"heartbeat", which is driven by the Amiga's timer chips at a rate of 600
ticks per second. The heartbeat clock pulses are then distributed to the
conductors, which are then distributed to the various players. (Historical
note: The RealTime Heartbeat was originally 500 Hz (2 ms per tick),
however a number of people requested that the tick rate be an even
multiple of the NTSC, PAL and motion picture frame rates (30, 25 and 24
Hz, respectively)).
    Each conductor keeps track of the variables that pertain to a
particular timing context. These include:

    -- the state of the conductor, i.e. running, stopped, paused,
        locating, etc.
    -- what time it is, relative to some agreed-upon "start time".
    -- whether the conductor is being driven by an external source such as
        SMPTE.

Time Formats
~~~~~~~~~~~~
    Often times, and application will want to receive timing information
in its own particular format. Particularly, a music program might want to
scale the current clock time based on the current tempo setting, a video
application might want to format the time into SMPTE format, etc. RealTime
provides a way for applications to attach an application-specific
conversion function to their player.
    In addition, there is an added complexity having to do with music
programs. RealTime itself only deals in 600Hz ticks -- it has no
understanding of things such as tempo, accelerando, ritardando, rubato,
etc. It is up to the application to provide these features, by scaling the
incoming clock times based on its current internal variables. The
suggested method for doing this is to use delta-times -- i.e. take the
current conductor time, subtract the previous conductor time, multiply or
divide that by the current tempo scaling factor, and add that to the
musical time counter. Of course, the program must save the remainder and
add it into the calculation for the next time if they want any sort of
long term accuracy (with this method, you can get very long term accuracy
needed for motion picture work).
    A special field has been provided in the PlayerInfo structure for
storing application- specific time, called pi_MetricTime (Issue: May be
changed to pi_ApplicationTime or pi_FormattedTime).
    A second complexity occurs when more than one music application is
playing. Since each application will be using a different algorithm for
computing tempo, it is likely that music applications would soon go out of
sync, even though they are being fed the same clock pulses. For example,
one program might support accelerando (the ability to gradually play
faster and faster), while another might only support immediate changes to
the playback rate.
	In order to resolve this problem, each Conductor contains a way for
musically-aware applications to distribute musical timing information
between themselves, in addition to the non-musical timing information
provided by RealTime. The conductor contains a field called cdt_Metronome,
which is used to store the current musical time (in 480ths of a quarter
note [Issue: I think this is a good number]). For each conductor,
RealTime will attempt to find the first musically-aware application on
its PlayerInfo list. (Note: The application must indicate that it is
musically aware by setting the PLAYER_Conducted tag attribute). The first
application so found is designated as the "Maestro" and gets to set the
musical time for all other musically aware applications. It is the duty of
the Maestro to fill in the cdt_Metronome so that other musically aware
applications can use it.
    Since the PlayerInfo list is kept in order by node priority,
applications which are more sophisticated about tempo should set their
node priority to a higher number so that they can get to be the Maestro,
thus allowing the other applications to take avantage of their superior
features (Optionally, the player priority could be user-settable). Here
are some suggestions for PlayerInfo priorities:

    less than zero          -- limited control of tempo (slow, fast, etc).
    0-9                     -- single-rate tempo (no tempo changes)
    10-19                   -- supports instantaneous tempo changes
    20-29                   -- supports accelerando / deccelarando
    30-39                   -- supports rubato, "human" tempos, or special
                                effects such as playing at half-speed, etc.

    Once the cdt_Metronome has been filled in, a special bit,
CONDUCTF_METROSET, will be set indicating that the metronome has been set.
Then other applications can check to see if the bit is set and use the
time -- if the bit is not set, then they must be the Maestro, so they must
set the bit and fill in the cdt_Metronome.
    What this means is that any application that looks at cdt_Metronome,
no matter how simple, must tell RealTime that it is musically aware (using
the PLAYER_Conducted tag), and must take responsibility for the fact that
it may end up being the Maestro.

Negative Time
~~~~~~~~~~~~~
    Note that all time formats are allowed to be negative. There are a
number of cases where a negative time might occur:
    -- A SMPTE reader is hooked up and it contains an "offset" feature,
but the videotape has been rewound to a point before the offset.
    -- A musical application which allows a "count-down" before the music
actually starts.
    However, none of the time formats may go backwards while the clock is
running. They must proceed monotonically forward, if they move at all.

Ready Bits
~~~~~~~~~~
    Each PlayerInfo maintains a "ready bit" which is used to tell RealTime
that the player is ready to receive ticks. This bit is reset each time
that RealTime relocates the clock to a new time. The reason for the ready
bit is that some application need to find the appropriate location in the
score or sequence list before they can start playing. In some modes,
RealTime will wait until all the players are ready before starting the
clock. In other modes RealTime will start the clock immediately, but won't
send any clock pulses to a player that is not ready. Which of these two
cases occurs is up to the application which actually caused the clock to
start, however in practice it usually depends on whether the clock was
started by the user (who can afford to wait a moment), or by an external
timing source (which might not be capable of waiting).
    Players can change the state of their ready bit by using the
PLAYER_Ready tag attribute.

Conductor States
~~~~~~~~~~~~~~~~
    Conductors have basically 4 states:

    CLOCKSTATE_STOPPED: The clock is not running.
    CLOCKSTATE_PAUSED: From RealTime's point of view, this is identical to
            being stopped; However, some applications may wish to make a
            distinction between the two states.
    CLOCKSTATE_LOCATING: Tells RealTime to start the clock, but only when
            all players are ready. When all players are ready, RealTime will
            then automatically go into Running mode. Players can change
            their "ready" state using the PLAYER_Ready tag attribute.
    CLOCKSTATE_RUNNING: The clock is started, and time pulses are being
            distributed to any applications are ready. Note that if the
            clock is set to "running" mode directly (without going to
            locate mode) then the applications will have to "catch up" as
            best they can (like a man chasing after a train leaving the
            station). This happens all the time in music applications and
            is normally not a problem -- generally what happens is that the
            applications play silently to themselves (perhaps sending out
            control information to make sure that external devices are in
            the right state when we start playing for real), and then start
            playing for real when they finally catch up.

    Any player may change the conductor state at any time by calling:

        SetConductorState(playerinfo, newstate, clocktime);

    (Clocktime is ignored for stopped and paused states).

    There is a special "fifth state" that is not really a state, called
CLOCKSPECIAL_METRIC. When you call SetConductorState() with this state,
what RealTime does is send a message to the Maestro (i.e. the ranking
musically-aware application) asking it to locate in musical time, rather
than in clock ticks. The Maestro will use its internal tempo conversion
routine, tempo map, or whatever application specific method it uses, to
convert the time from metronome units to 600 Hz RealTime clock units. Then
the Maestro should set the clock state to CLOCKSTATE_LOCATE with the newly
computed time.
    What this does is allows any musically-aware application to locate the
clock to a particular measure or note, yet still utilize the superior
timing features of the current Maestro application. For example, you may
want to start playing "at the third measure". RealTime has no concept of
"measures", so it's up to the maestro to tell RealTime what that means in
terms of actual clock time.
	Note that this will probably take slightly longer than a regular
locate, because the Maestro may need to do an internal locate first to do
the time computation.

Creating a Conductor
~~~~~~~~~~~~~~~~~~~~
    Conductors are created automatically whenever any player attempts to
refer to them, and are deleted whenever the number of players referring to
them falls to zero.

Creating a Player
~~~~~~~~~~~~~~~~~
    To create a player, you'll need to call CreatePlayerA(), which takes a
taglist of options that specify the name of the player, the name of the
conductor to attach it to (or create if it doesn't already exist), the
priority of the player in the player list, etc. There are also tag items
to set the player ID and UserData fields, which are available for
application-specific use.
    The PLAYER_ID attribute deserves special attention. This can be used
by applications to distinguish one player from another, which might be
useful in cases where an application has more than one PlayerInfo. For
example, a music sequencer might want a normal player for playing music,
and a special player attached to a "private" conductor (see the autodocs
on how to do this). The private conductor would be used to provide timing
for the program's internal features such as timeouts, feedback notes, and
other things that normally would not be synchronized to other
applications. (Private conductors are basically used for anything that you
would normally want to use an Amiga CIA timer for.)

    A player's attributes can be changed later by calling SetPlayerAttrs().
In addition, SetPlayerAttrs is also used for a number of other things, for
example to set the ready bit for the player.

    Players are deleted by calling DeletePlayer();

Alarms
~~~~~~
    Each player has an "alarm" which will cause a signal to go off when
the application reaches a specified time. Note that the alarm field is
checked against the pi_MetricTime, not the conductor time, which means
that the alarm can be in the application's own format. (Note that if there
is no player hook, the conductor time will be copied into the
pi_MetricTime field so that alarms still work).
    Alarms are set using the PLAYER_SignalTask, PLAYER_AlarmSigBit,
PLAYER_AlarmTime and PLAYER_AlarmOn tags.

Player Hooks
~~~~~~~~~~~~
	Players can have a callback hook which is invoked at each clock tick,
but only while the clock is running, and only if the player is ready
(there are some other criterion as well, for example if the clock has
somehow advances beyond external sync it will freeze until the external
time source can catch up). The hook is set up using the PLAYER_Hook tag.
    A properly written player hook will have a number of tasks to perform.
First off, there are three possible "messages", or event types, which can
invoke the player hook, and each carries a different data structure and
must be handled differently:

    -- clock ticks (indicated by PM_TICK method)
    -- clock state changes (indicated by PM_STATE method)
    -- clock special locate (inidicated by PM_POSITION method)

    Here is an overview of how a player hook which supports all possible
features might look:

    determine type of message:

        case PM_TICK:

            get the current tick number from the hook message

            if we are a musically-aware application:

                If CONDUCTF_METROSET is set
                    get the time from cdt_Metronome.
                else
                    convert the tick to musical time (perhaps using
                    delta-time calculations), and place in
                    cdt_Metronome.

                    set the CONDUCTF_METROSET flag
                endif

                convert the cdt_Metronome time, or the current tick number
                (whichever is preferred by the application) to application-
                specific format and place in pi_MetricTime.

            else

                convert tick number to application-specific format
                (perhaps using delta-time calculations) and place in
                pi_MetricTime.

            endif

        case PM_STATE:

            signal application main task that we changed state

        case PM_POSITION:

			from the hook message, get the musical time to locate to and
				save in a variable.
            signal main task that a "special locate" has been requested.

External Synchronization
~~~~~~~~~~~~~~~~~~~~~~~~
    Each RealTime conductor has a special external sync input, which can
be used to force the conductor to synchronize with an external timing
source.
    Applications which want to feed external time pulses into a Conductor
must also be a player, so that the conductor will remain in existence.
However, some specialized applications (such a SMPTE reader utility) will
not need all the features of a full PlayerInfo, so a special tag,
PLAYER_Quiet, has been defined which allows for a "placeholder" PlayerInfo
to be created. This inactive player will always be skipped over during
time distribution.
    The second thing required is that the application must inform the
Conductor that it wishes to take over. This is done by setting the
PLAYER_ExtSync attribute using SetPlayerAttrs(). This call is neccessary
because there can only be one external sync source per Conductor, and
RealTime needs to arbitrate these. (Note that the call can fail).
    Finally, the function must call ExternalSync() each time it gets an
external sync call. ExternalSync has three parameters:
    -- the address of the player
    -- the current time (in 600 Hz units)
    -- the estimated time of the next external clock tick.

    The reason for the third parameter is to allow the Conductor to
interpolate between external ticks. For example, suppose you have a SMPTE
reader which has external ticks coming in a 30 frames per second. Suppose
that frame #15 has just occured, which corresponds to 300 RealTime clock
ticks. Since each external clock tick (1/30th of a second) corresponds to
20 RealTime clock ticks, the estimated time of the next external clock
tick is 320.
    What this does is allow the conductor to run at its normal 600 Hz
rate, however the clock values are clamped between the values 300 and 320.
(with the stipulation that the clock can never go backwards if it's
already too far ahead). Thus, the applications get the benefit of 2 ms
timing accuracy, but can still maintain synchronization with the external
source.

    Note that since the external sync application as a PlayerInfo, it can
start and stop the clock. This feature is primarily designed for devices
such as SMPTE readers -- the sync driver could have a feature to allow the
clock to be started automatically whenever the sync driver senses the tape
is moving. Thus, all the user has to do is press "play" on the videotape
player, and all of his music and animations start playing along
automatically, and in perfect synchronization.

    One other thing to note is that even when the clock is in "running"
state, and all the applications are ready, the Conductor will not
distribute any clock ticks until the first external clock tick is
received. This prevents "false starts" and other inconvenient effects.

Credits
~~~~~~~
	RealTime was envisioned by David Joiner (a.k.a. Talin) and implemented
by Joe Pearce. Bill Barton also made a number of important suggestions.
