/*******************************Module*Header*********************************
* Module Name: mmseqi.h
*
* MultiMedia Systems MIDI Sequencer DLL Internal prototypes and data struct's
*
* Created: 4/10/90
* Author:  GREGSI
*
* History:
*
* Copyright (c) 1985-1991 Microsoft Corporation
*
\****************************************************************************/
/*****************************************************************************
 *
 *                          Constants
 *
 ****************************************************************************/
//#define SEQDEBUG 1

// max. tracks allowed in a sequence

#define MAXTRACKS           100

//  MIDI real time data:

#define SysExCode           257
#define MetaEventCode       258

#define METAEVENT           0XFF
#define SYSEX               0XF0
#define SYSEXF7             0XF7
#define PROGRAMCHANGE       0xC0

// packet codes:  these are flags

#define LASTPACKET          0X1
#define FIRSTPACKET         0X2

// META EVENT TYPES

#define ENDOFTRACK          0X2F
#define TEMPOCHANGE         0X51
#define SMPTEOFFSET         0X54
#define TIMESIG             0X58
#define SEQSTAMP            0X7F

// PORT TYPES

#define TRACKPORT           0
#define OUTPORT             1
#define CONTROLPORT         2
#define METAPORT            3

/* fileStatus codes */

#define NoErr               256
#define EndOfStream         257
#define AllTracksEmpty      258
#define OnlyBlockedTracks   259
#define AtLimit 	    260
#define InSysEx 	    261

/* Blocking types */

#define not_blocked         0

// these imply that you're blocked on input (waiting for free input buffer)

#define between_msg_out     270
#define in_rewind_1	    271
#define in_rewind_2	    272
#define in_ScanEarlyMetas   273
#define in_Normal_Meta	    274
#define in_SysEx	    275
#define in_Seek_Tick	    276
#define in_Seek_Meta	    277
#define in_SkipBytes_Seek   278
#define in_SkipBytes_ScanEM 279
#define in_SkipBytes_Play   280

/* Generic types -- used temporarily at a low level */
#define on_input            350

// End of blocking types.

#define NAMELENGTH          32

/*
   codes to pass to SendAllEventB4 (called in normal course of playing, and
   by song pointer code for chase-lock)
*/

#define MODE_SEEK_TICKS     1
#define MODE_PLAYING        2
#define MODE_SILENT         3
#define MODE_SCANEM         4


// Code to hold in seq->SeekTickToBe when there is no seek pending

#define NotInUse            ((DWORD)-1L)

/* delta-time escapes ("legal" deltas only use 28 bits) */

#define MAXDelta            0X8FFFFFFF
#define TrackEmpty          0X8FFFFFFE

#define MHDR_LASTBUFF	    2
extern UINT MINPERIOD;

typedef int                 FileStatus;    // this not thoroughly defined

/*****************************************************************************
 *
 *                        Data Stuctures & Typedefs
 *
 ****************************************************************************/

/* USED FOR BYTE MANIPULATION OF MIDI DWORDS */
typedef struct fbm    // 32 bit -- passed in lparam
{
    BYTE    status;      // (order may change for optimization)
    BYTE    byte2;
    BYTE    byte3;
    BYTE    time;
} FourByteMIDI;

typedef union
{
    DWORD        wordMsg;
    FourByteMIDI byteMsg;
} ShortMIDI;

/* USED TO HOLD LONG MIDI (SYSEX) INFORMATION */
// size of data buffer
#define LONGBUFFSIZE 0x100
// number of buffers in array (held in seq struct)
#define NUMSYSEXHDRS 2

#define	pSEQ(h)	((NPSEQ)(h))
#define	hSEQ(p)	((HMIDISEQ)(p))

typedef struct lm    // ptr to this passed in lparam
{
    MIDIHDR midihdr; // embedded midihdr struct
    BYTE    data[LONGBUFFSIZE];
} LongMIDI;

typedef LongMIDI NEAR * NPLONGMIDI;

/* USED FOR KEEPING TRACK OF CERTAIN EVENTS (META/KEY/PATCH) */
typedef struct    // bit vector of booleans
{
    WORD    filter[8];   // yields 128 booleans
} BitVector128;

/* DATA STRUCTURES TO HOLD CONTENTS OF META EVENT READ IN */

typedef struct
{
    BYTE    hour;
    BYTE    minute;
    BYTE    second;
    BYTE    frame;
    BYTE    fractionalFrame;
} SMPTEType;

typedef struct
{
    int     numerator;
    int     denominator;
    int     midiClocksMetro;
    int     thirtySecondQuarter;
} TimeSigType;


/* TEMPO MAP ELEMENT (for list of tempo changes to facilitate ms <-> beat
   conversion) */

typedef struct tag_TempoMapElement
{
    DWORD   dwMs;
    DWORD   dwTicks;
    DWORD   dwTempo;
} TempoMapElement;

typedef TempoMapElement *NPTEMPOMAPELEMENT;

typedef struct t1
{
    LPBYTE      currentPtr;     //points at current byte in stream
    LPBYTE      endPtr;         //points at last byte in buffer
    LPBYTE      previousPtr;    //points at beginning of previous message
    LPMIDISEQHDR hdrList;        // list of track data headers
} TLevel1;


/* SEQUENCE TRACK DATA STRUCTURE */

typedef struct trk
{
    int         blockedOn;          // how blocked, if at all?
    LONG	delta;              // time in ticks 'till next event fired
    DWORD	length; 	    // length of this track in ticks
    BYTE        lastStatus;         // used for running status
    ShortMIDI   shortMIDIData;      // staging area for next event
    LONG        sysExRemLength;     // remaining length when sysex pending
    TLevel1     inPort;             // low level data pertaining to file
    BOOL        endOfTrack;         // whether track is at end of its data
    int         iTrackNum;          // track number (0-based)
    DWORD       dwCallback;         // address of callback routine in mciseq
                                    //   used to return buffer to it (so it
                                    //   can be refilled and received again)
    DWORD       dwInstance;         // mciseq's private instance information
                                    //  (usually contains file handle...)
    DWORD       dwBytesLeftToSkip;
} TRACK;

typedef TRACK NEAR *NPTRACK;

typedef struct trackarray_tag
{
    NPTRACK trkArr[];
} TRACKARRAY;
typedef TRACKARRAY NEAR * NPTRACKARRAY;

// fwFlags:
#define	LEGALFILE	0x0001		// Is a legal MIDI file
#define	GENERALMSMIDI	0x0002		// Is an MS General MIDI file

typedef struct seq_tag
{
    int         divType;            // PPQN, SMPTE24, SMPTE25, SMPTE30,
                                    //   or SMPTE30Drop
    int         resolution;         // if SMPTE, ticks/frame, if MIDI,
                                    //   ticks/q-note
    BOOL	playing;	    // whether sequence playing or not
    DWORD	playTo; 	    // what tick to play to, if not end
                                    //   (used for mci_play_to command)
    DWORD	length; 	    // length of sequence in ticks
    BOOL        readyToPlay;        // whether sequence is set up to play
    DWORD       currentTick;        // where we are rel. to beginning of song
    DWORD       nextExactTime;      // system time (ms) that next event
                                    //   *should* occur at
    BOOL        withinMsgOut;       // true iff in middle of sending a message
    DWORD       seekTicks;          // temp for seektick or song ptr operation
    DWORD       tempo;              // tempo of sequence in ticks per Usec.
    MMTIME	smpteOffset;	    // absolute smpte time of start of seq.
                                    //   from meta event, or user)
    TimeSigType timeSignature;      // current time signature of piece (can
                                    //   change)
    ListHandle  trackList;          // track list handle
    NPTRACK     nextEventTrack;     // track that next event resides in
    NPTRACK     firstTrack;         // track holding tempos, smpte offset...
    char        Name[NAMELENGTH];   // name of the sequence

    // sync-related stuff below

    DWORD       nextSyncEventTick;  // global tick at which the next sync
                                    // event is expected
    WORD 	slaveOf;	    // what you're slave of (mtc, clock,
                                    //   file, or nothing)
    WORD 	masterOf;	    // what you're slave of (mtc, clock,
                                    //   or nothing)
    BOOL        waitingForSync;     // tells if currently 'blocked' waiting
                                    // for a sync pulse
//  BitVector128      extMetaFilter;      // for each meta type, whether to send it.
                                    //   (unused for now)
    BitVector128      intMetaFilter;      // for each meta type, whether it
                                    //   affects seq.
    DWORD       dwTimerParam;       // used after timer interrupt to remember
                                    //   how many ticks elapsed
    UINT        wTimerID;           // handle to timer (used to cancel
                                    //   next interrupt.
    HMIDIOUT	hMIDIOut;	    // handle to midi output driver
    HANDLE      hStream;            // handle to stream
    UINT	wCBMessage;	    // message type that notify is for
    ListHandle	tempoMapList;	    // list of tempo map items for
                                    //   ms <-> ppqn conversion.
    BOOL	bSetPeriod;	    // whether timer period is currently
                                    //   set or not.
    PATCHARRAY  patchArray;	    // arrays to keep track of which
                                        //   patches used
    KEYARRAY    drumKeyArray;       // array for drum cacheing
    BitVector128 keyOnBitVect[16];  // arrays to keep track of which
                                        //   patches used
    BOOL        bSending;           // currently in sendevent loop
                                    // (used to prevent reentrancy)
    BOOL        bTimerEntered;      // (used to prevent timer reentrancy)
#ifdef DEBUG
    DWORD       dwDebug;            // debug signature (for detecting bogus
                                    //   seq ptr)
#endif
    NPTRACKARRAY  npTrkArr;         // pointer to track array
                                    // (used for routing incoming trk data)
    UINT        wNumTrks;           // number of tracks
    LongMIDI    longMIDI[NUMSYSEXHDRS + 1]; // list of long midi buffers
    BYTE        bSysExBlock;        // whether blocked waiting for long buff
    BYTE        bSendingSysEx;      // whether in mid sysex out
    UINT        fwFlags;            // various flags
} SEQ;

typedef SEQ NEAR *NPSEQ;

/****************************************************************************
 *
 *                         Prototypes
 *
 ***************************************************************************/

// MMSEQ.C
PRIVATE VOID NEAR PASCAL SeekTicks(NPSEQ npSeq);
PUBLIC  UINT NEAR PASCAL GetInfo(NPSEQ npSeq, LPMIDISEQINFO lpInfo);
PUBLIC  UINT NEAR PASCAL CreateSequence(LPMIDISEQOPENDESC lpOpen,
            LPHMIDISEQ lphMIDISeq);
PUBLIC  VOID NEAR PASCAL FillInDelta(NPTRACK npTrack);
PUBLIC  UINT NEAR PASCAL Play(NPSEQ npSeq, DWORD dwPlayTo);
PUBLIC  VOID NEAR PASCAL Stop(NPSEQ npSeq);
PUBLIC  UINT NEAR PASCAL TimerIntRoutine(NPSEQ npSeq, LONG elapsedTick);
PUBLIC  VOID NEAR PASCAL SetBlockedTracksTo(NPSEQ npSeq,
            int fromState, int toState);
PUBLIC  VOID NEAR PASCAL ResetToBeginning(NPSEQ npSeq) ;
PUBLIC  BOOL NEAR PASCAL HandleMetaEvent(NPSEQ npSeq, NPTRACK npTrack,
            UINT wMode);
PUBLIC  BOOL NEAR PASCAL ScanEarlyMetas(NPSEQ npSeq, NPTRACK npTrack,
            DWORD dwUntil);
PUBLIC  FileStatus NEAR PASCAL SendAllEventsB4(NPSEQ npSeq,
            LONG elapsedTick, int mode);
PUBLIC  FileStatus NEAR PASCAL GetNextEvent(NPSEQ npSeq);
PUBLIC  VOID NEAR PASCAL FillInNextTrack(NPTRACK npTrack);
PUBLIC  UINT NEAR PASCAL SendPatchCache(NPSEQ npSeq, BOOL cache);
PUBLIC  VOID NEAR PASCAL SendSysEx(NPSEQ npSeq);
PUBLIC  VOID NEAR PASCAL SkipBytes(NPTRACK npTrack, LONG length);


// UTIL.C

PUBLIC VOID NEAR PASCAL seqCallback(NPTRACK npTrack, UINT msg,
        DWORD dw1, DWORD dw2);
PUBLIC BYTE NEAR PASCAL LookByte(NPTRACK npTrack);
PUBLIC BYTE NEAR PASCAL GetByte(NPTRACK npTrack);
PUBLIC VOID NEAR PASCAL MarkLocation(NPTRACK npTrack);
PUBLIC VOID NEAR PASCAL ResetLocation(NPTRACK npTrack);
PUBLIC VOID NEAR PASCAL RewindToStart(NPSEQ npSeq, NPTRACK npTrack);
PUBLIC BOOL NEAR PASCAL AllTracksUnblocked(NPSEQ npSeq);
PUBLIC VOID FAR PASCAL _LOADDS OneShotTimer(UINT wId, UINT msg, DWORD dwUser,
        DWORD dwTime, DWORD dw2);
PUBLIC UINT NEAR PASCAL SetTimerCallback(NPSEQ npSeq, UINT msInterval,
        DWORD elapsedTicks);
PUBLIC VOID NEAR PASCAL DestroyTimer(NPSEQ npSeq);
PUBLIC VOID NEAR PASCAL SendLongMIDI(NPSEQ npSeq,
        LongMIDI FAR *pLongMIDIData);
PUBLIC UINT NEAR PASCAL NewTrackData(NPSEQ npSeq, LPMIDISEQHDR msgHdr);
PUBLIC NPLONGMIDI NEAR PASCAL GetSysExBuffer(NPSEQ npSeq);


// CRIT.ASM

extern FAR PASCAL EnterCrit(void);
extern FAR PASCAL LeaveCrit(void);

// CALLBACK.C

PUBLIC VOID  FAR  PASCAL _LOADDS MIDICallback(HMIDIOUT hMIDIOut, UINT wMsg,
       DWORD dwInstance, DWORD dwParam1, DWORD dwParam2);

PUBLIC VOID FAR PASCAL NotifyCallback(HANDLE hStream);