/*==========================================================================
 *
 *  Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
 *
 *  File:	midstuff.h
 *  Content:	MIDI structures and definitions used by the MSTREAM sample
 *              application in converting a MID file to a MIDI stream for
 *              playback using the midiStream API.
 *
 ***************************************************************************/
#ifndef __MIDSTUFF_H__
#define __MIDSTUFF_H__

// MIDI file constants
//
#define MThd		0x6468544D		// Start of file
#define MTrk		0x6B72544D		// Start of track

#define MIDI_SYSEX	((BYTE)0xF0)		// SysEx begin
#define MIDI_SYSEXEND	((BYTE)0xF7)		// SysEx begin
#define MIDI_META	((BYTE)0xFF)		// Meta event begin
#define MIDI_META_TEMPO	((BYTE)0x51)		// Tempo change
#define MIDI_META_EOT	((BYTE)0x2F)		// End-of-track

#define MIDI_NOTEOFF	((BYTE)0x80)		// + note + velocity
#define MIDI_NOTEON	((BYTE)0x90)		// + note + velocity
#define MIDI_POLYPRESS  ((BYTE)0xA0)		// + pressure (2 bytes)
#define MIDI_CTRLCHANGE ((BYTE)0xB0)		// + ctrlr + value
#define MIDI_PRGMCHANGE	((BYTE)0xC0)		// + new patch
#define MIDI_CHANPRESS	((BYTE)0xD0)		// + pressure (1 byte)
#define MIDI_PITCHBEND	((BYTE)0xE0)		// + pitch bend (2 bytes)

#define NUM_CHANNELS	16

#define MIDICTRL_VOLUME		((BYTE)0x07)
#define MIDICTRL_VOLUME_LSB	((BYTE)0x27)
#define MIDICTRL_PAN		((BYTE)0x0A)

#define MIDIEVENT_CHANNEL(dw)	(dw & 0x0000000F)
#define MIDIEVENT_TYPE(dw)	(dw & 0x000000F0)
#define MIDIEVENT_DATA1(dw)	((dw & 0x0000FF00) >> 8)
#define MIDIEVENT_VOLUME(dw)	((dw & 0x007F0000) >> 16)

// Macros for swapping hi/lo-endian data
//
#define WORDSWAP(w)	(((w) >> 8) | \
			(((w) << 8) & 0xFF00))

#define DWORDSWAP(dw) 	(((dw) >> 24) |			\
			(((dw) >> 8) & 0x0000FF00) |	\
			(((dw) << 8) & 0x00FF0000) |	\
			(((dw) << 24) & 0xFF000000))

// In debug builds, TRACKERR will show us where the parser died
//
#ifdef DEBUG
#define TRACKERR(p,sz) ShowTrackError(p,sz);
#else
#define TRACKERR(p,sz)
#endif


// Make a little distinction here so the various structure members are a bit
// more clearly labelled -- we have offsets and byte counts to keep track of
// that deal with both in-memory buffers and the file on disk

#define	FILEOFF	DWORD
			

// These structures are stored in MIDI files; they need to be byte aligned.
//
#pragma pack(1)

// Chunk header. dwTag is either MTrk or MThd.
//
typedef struct
{
    DWORD	dwTag;			// Type
    DWORD	dwChunkLength;		// Length (hi-lo)
} MIDICHUNK;

// Contents of MThd chunk.
typedef struct
{
    WORD	wFormat;		// Format (hi-lo)
    WORD	wTrackCount;		// # tracks (hi-lo)
    WORD	wTimeDivision;		// Time division (hi-lo)
} MIDIFILEHDR;

#pragma pack() // End of need for byte-aligned structures


// Temporary event structure which stores event data until we're ready to
// dump it into a stream buffer
//
typedef struct
{
    DWORD	tkEvent;	// Absolute time of event
    BYTE	byShortData[4];	// Event type and parameters if channel msg
    DWORD	dwEventLength;	// Length of data which follows if meta or sysex
    LPBYTE	pLongData;	// -> Event data if applicable
} TEMPEVENT, *PTEMPEVENT;

#define ITS_F_ENDOFTRK	0x00000001

// Description of a track open for read
//
typedef struct
{
    DWORD	fdwTrack;	// Track status
    DWORD	dwTrackLength;	// Total bytes in track
    DWORD	dwLeftInBuffer;	// Bytes left unread in track buffer
    LPBYTE	pTrackStart;	// -> start of track data buffer
    LPBYTE	pTrackCurrent;	// -> next byte to read in buffer
    DWORD	tkNextEventDue;	// Absolute time of next event in track
    BYTE	byRunningStatus;// Running status from last channel msg

    FILEOFF	foTrackStart;	// Start of track -- used for walking the file
    FILEOFF	foNextReadStart;// File offset of next read from disk
    DWORD	dwLeftOnDisk;	// Bytes left unread on disk
#ifdef DEBUG
    DWORD	nTrack;		// # of this track for debugging
#endif
} INTRACKSTATE, *PINTRACKSTATE;

// Description of the input MIDI file
//
typedef struct
{
    DWORD	cbFileLength;		// Total bytes in file
    DWORD	dwTimeDivision;		// Original time division
    DWORD	dwFormat;		// Original format
    DWORD	dwTrackCount;		// Track count (specifies pitsTracks size)
    INTRACKSTATE *pitsTracks;		// -> array of tracks in this file
} INFILESTATE, *PINFILESTATE;

#endif

