#ifndef MIDI_REALTIME_H
#define MIDI_REALTIME_H
/************************************************************************
*     RealTime Library (timing & syncing system)                        *
*************************************************************************
*                                                                       *
* Design & Development  - Talin & Joe Pearce                            *
*                                                                       *
* Copyright 1992 by Commodore Business Machines                         *
*************************************************************************
*
* realtime.h  - RealTime conductor/player include file.
*
************************************************************************/

#ifndef EXEC_LISTS_H
  #include <exec/lists.h>
#endif

#ifndef EXEC_TYPES_H
  #include <exec/types.h>
#endif

#ifndef UTILITY_TAGITEM_H
  #include <utility/tagitem.h>
#endif

#ifndef UTILITY_HOOKS_H
  #include <utility/hooks.h>
#endif

/* Each Conductor represents a group of applications which wish to remain
 * synchronized together. 
 */

struct Conductor {
    struct Node		cdt_Node;		/* conductor list node		*/
    UWORD		cdt_nodepad;
    struct MinList	cdt_Players;		/* list of players		*/
    ULONG		cdt_ClockTime,		/* current time of this sequence*/
			cdt_StartTime,		/* start time of this sequence	*/
			cdt_ExternalTime,	/* time from external unit	*/
			cdt_MaxExternalTime,	/* upper limit on sync'd time	*/
			cdt_Metronome;		/* MetricTime highest pri node  */
    UWORD		cdt_PlayersNotReady;	/* count of players not ready	*/
    UWORD		cdt_Flags;		/* clock flags			*/
    UBYTE		cdt_State;		/* playing or stopped		*/
    UBYTE		cdt_Stopped;		/* quick stopped check		*/
};

#define CONDUCTF_EXTERNAL	(1<<0)		/* clock is externally driven	*/
#define CONDUCTF_GOTTICK	(1<<1)		/* received 1st external tick	*/
#define CONDUCTF_METROSET	(1<<2)		/* Metroname filled in		*/

enum time_states {
    CLOCKSTATE_STOPPED=0,			/* clock is stopped		*/
    CLOCKSTATE_PAUSED,				/* clock is paused		*/
    CLOCKSTATE_LOCATE,				/* go to 'running' when ready	*/
    CLOCKSTATE_RUNNING,				/* run clock NOW		*/
    CLOCKSTATE_METRIC=-1,			/* ask high node to locate	*/
    CLOCKSTATE_SHUTTLE=-2			/* time changing but not running*/
						/* SetConductorState only	*/
};

#define CONDSTOPF_STOPPED	(1<<0)		/* not running state		*/
#define CONDSTOPF_NOTICK	(1<<1)		/* extsync & not gottick	*/

/* The PlayerInfo is the connetion between a Conductor and an application.
 */

struct PlayerInfo {
    struct Node		pi_Node;		/* callback for player		*/
    UWORD		pi_nodepad;
    struct Hook		*pi_Hook;		/* callback for player		*/
    struct Conductor 	*pi_Source;		/* pointer to parent context	*/
    struct Task		*pi_Task;		/* task to signal for alarm	*/
    LONG		pi_MetricTime;		/* current time in app's metric	*/
    LONG		pi_AlarmTime;		/* time to wake up		*/
    void		*pi_UserData;		/* for application use		*/
    UWORD		pi_PlayerID;		/* for application use		*/
    UWORD		pi_Flags;		/* general PlayerInfo flags	*/
    ULONG		pi_Reserved[2];		/* internal use			*/
    BYTE		pi_AlarmSigBit;		/* signal to send for alarms	*/
};

#define PLAYERF_READY	(1<<0)			/* player is ready to go!	*/
#define PLAYERF_ALARMSET (1<<1)			/* alarm is set			*/
#define PLAYERF_QUIET	(1<<2)			/* a dummy player, used for sync*/
#define PLAYERF_CONDUCTED (1<<3)		/* give me metered time		*/
#define PLAYERF_EXTSYNC (1<<4)			/* granted external sync	*/

#define PLAYER_Base	(TAG_USER+64)
#define PLAYER_Hook	(PLAYER_Base+1)		/* set address of hook function	*/
#define PLAYER_Name	(PLAYER_Base+2)		/* name of player		*/
#define PLAYER_Priority	(PLAYER_Base+3)		/* priority of player		*/
#define PLAYER_Conductor (PLAYER_Base+4)	/* set conductor for player	*/
						/* if ~0, create private conductor */
#define PLAYER_Ready	(PLAYER_Base+5)		/* the "ready" flag		*/
#define PLAYER_SignalTask (PLAYER_Base+6)	/* task to signal for alarm/notify */
#define PLAYER_Conducted (PLAYER_Base+7)	/* sets/clears CONDUCTED flag	*/
#define PLAYER_AlarmSigBit (PLAYER_Base+8)	/* signal bit for alarm (or -1) */
#define PLAYER_Quiet	(PLAYER_Base+9)		/* don't process time thru this */
#define PLAYER_UserData	(PLAYER_Base+10)
#define PLAYER_ID	(PLAYER_Base+11)
#define PLAYER_AlarmTime (PLAYER_Base+12)	/* alarm time (sets PLAYERF_ALARMSET) */
#define PLAYER_AlarmOn (PLAYER_Base+13)		/* sets/clears ALARMSET flag	*/
#define PLAYER_ExtSync (PLAYER_Base+14)		/* attempt/release to ext sync	*/

#define PLAYER_ErrorCode (PLAYER_Base+15)	/* error return value		*/

/* Mesages sent via PlayerInfo hook.
 */

enum player_methods {
    PM_TICK=0,
    PM_STATE,
    PM_POSITION,
	PM_SHUTTLE
};

struct pmTime {		/* used for PM_TICK, PM_POSITION and PM_SHUTTLE */
    ULONG		pmt_Method;
    ULONG		pmt_Time;
};

struct pmState {	/* used for PM_STATE */
    ULONG		pms_Method;
    ULONG		pms_OldState;
};

enum {
    RT_Conductors,                              /* conductor list */
    RT_NLocks
};

/***************************************************************
*
*   RealTime Error Codes
*
***************************************************************/

#define RTE_NoMem     801       /* memory allocation failed */
#define RTE_NoSignals 802       /* signal allocation failed */
#define RTE_NoTimer   803       /* timer (CIA) allocation failed */
#define RTE_Playing   804		/* Can't shuttle while playing */

#endif /* MIDI_REALTIME_H */
