Exemplo n.º 1
0
/* GetTrackEvent
 *
 * Fills in the event struct with the next event from the track
 *
 * te->event_time will contain the absolute tick time of the event.
 *
 * te->shortdata[0] will contain:
 * - MIDI_META_EVENT if the event is a meta event; in this case
 *   te->shortdata[1] will contain the meta class.
 * - MIDICMD_SYSEX or MIDICMD_SYSEX_END if the event is a SysEx event
 * - Otherwise, event is a channel message and te->shortdata[1] and
 *   te->shortdata[2] will contain the rest of the event.
 *
 * te->event_len will contain:
 * - The total length of the channel message in te->shortdata if the
 *   event is a channel message,
 * - The total length of the paramter data pointed to by te->longdata,
 *   otherwise.
 *
 * te->longdata will point at any additional paramters if the event is
 * a SysEx or meta event with non-zero length; else it will be NULL.
 *
 * Returns zero on success or non-zero on any kind of parse error
 * Maintains the state of the input track (i.e. ts->left_in_buffer,
 * ts->pTrackPointers, and ts->running_status).
 */
static int GetTrackEvent (track_state_t *ts, temp_event_t *te)
{
	DWORD	idx;
	BYTE	b;
	UINT	event_len;

	/* Clear out the temporary event structure to get rid of old data */
	memset(te, 0, sizeof(struct _temp_event_s));

	/* Already at end of track? There's nothing to read. */
	if (ts->status & ITS_F_ENDOFTRK)
		return 1;
	if (!ts->left_in_buffer && !ts->left_on_disk)
		return 1;

	/* Get the first byte, which determines the type of event. */
	if (GetTrackByte(ts, &b))
		return 1;

	/* If the high bit is not set, then this is a channel message
	 * which uses the status byte from the last channel message
	 * we saw. NOTE: We do not clear running status across SysEx or
	 * meta events even though the spec says to because there are
	 * actually files out there which contain that sequence of data.
	 */
	if ( !(b & 0x80))
	{
		/* No previous status byte? We're hosed. */
		if (!ts->running_status)
		{
			TRACKERR(ts, err_bad_runstat);
			return 1;
		}

		te->shortdata[0] = ts->running_status;
		te->shortdata[1] = b;

		b = te->shortdata[0] & 0xF0;
		te->event_len = 2;

		/* Only program change and channel pressure events are
		 * 2 bytes long.  the rest are 3 and need another byte. */
		if (b != MIDICMD_PGM_CHANGE && b != MIDICMD_CHANNEL_PRESSURE)
		{
			if (!ts->left_in_buffer && !ts->left_on_disk)
			{
				TRACKERR(ts, err_trunc_runstat);
				ts->status |= ITS_F_ENDOFTRK;
				return 1;
			}

			if (GetTrackByte(ts, &te->shortdata[2]))
				return 1;
			++te->event_len;
		}
	}
	else if ((b & 0xF0) != MIDICMD_SYSEX)
	{
		/* Not running status, not in SysEx range - must be
		 * normal channel message (0x80-0xEF)  */
		te->shortdata[0] = b;
		ts->running_status = b;

		/* Strip off channel and just keep message type */
		b &= 0xF0;

		event_len = (b == MIDICMD_PGM_CHANGE || b == MIDICMD_CHANNEL_PRESSURE) ? 1 : 2;
		te->event_len = event_len + 1;

		if ((ts->left_in_buffer + ts->left_on_disk) < event_len)
		{
			TRACKERR(ts, err_trunc_chan_msg);
			ts->status |= ITS_F_ENDOFTRK;
			return 1;
		}

		if (GetTrackByte(ts, &te->shortdata[1]))
			return 1;

		if (event_len == 2)
		{
			if (GetTrackByte(ts, &te->shortdata[2]))
				return 1;
		}
	}
	else if (b == MIDICMD_SYSEX || b == MIDICMD_SYSEX_END)
	{
		/* One of the SysEx types. (They are the same as far as we're
		 * concerned; there is only a semantic difference in how the
		 * data would actually get sent when the file is played.
		 * We must take care to put the proper event type back on the
		 * output track, however.)
		 *
		 * Parse the general format of:
		 *	BYTE	event (MIDICMD_SYSEX or MIDICMD_SYSEX_END)
		 *	VDWORD	num_parms
		 *	BYTE	ab_parms[num_parms]
		 */
		te->shortdata[0] = b;
		if (GetTrackVDWord(ts, &te->event_len))
		{
			TRACKERR(ts, err_trunc_sysex_len);
			return 1;
		}

		if ((ts->left_in_buffer + ts->left_on_disk) < te->event_len)
		{
			TRACKERR(ts, err_trunc_sysex);
			ts->status |= ITS_F_ENDOFTRK;
			return 1;
		}

		te->longdata = (BYTE *) Z_Malloc(te->event_len, Z_MAINZONE);
		for (idx = 0; idx < te->event_len; idx++)
		{
			if (GetTrackByte(ts, te->longdata + idx))
			{
				Z_Free(te->longdata);
				te->longdata = NULL;
				TRACKERR(ts, err_trunc_sysex);
				return 1;
			}
		}
	}
	else if (b == MIDI_META_EVENT)
	{
		/* It's a meta event. Parse the general form:
		 *	BYTE	event (MIDI_META_EVENT)
		 *	BYTE	class
		 *	VDWORD	num_parms
		 *	BYTE	ab_parms[num_parms]
		 */
		te->shortdata[0] = b;

		if (!ts->left_in_buffer && !ts->left_on_disk)
		{
			TRACKERR(ts, err_meta_noclass);
			ts->status |= ITS_F_ENDOFTRK;
			return 1;
		}

		if (GetTrackByte(ts, &te->shortdata[1]))
			return 1;

		if (GetTrackVDWord(ts, &te->event_len))
		{
			TRACKERR(ts, err_trunc_meta_len);
			return 1;
		}

		/* NOTE: It's perfectly valid to have a meta with no data
		 * In this case, event_len == 0 and longdata == NULL */
		if (te->event_len)
		{
			if ((ts->left_in_buffer + ts->left_on_disk) < te->event_len)
			{
				TRACKERR(ts, err_trunc_meta);
				ts->status |= ITS_F_ENDOFTRK;
				return 1;
			}

			te->longdata = (BYTE *) Z_Malloc(te->event_len, Z_MAINZONE);
			for (idx = 0; idx < te->event_len; idx++)
			{
				if (GetTrackByte(ts, te->longdata + idx))
				{
					Z_Free(te->longdata);
					te->longdata = NULL;
					TRACKERR(ts, err_trunc_meta);
					return 1;
				}
			}
		}

		if (te->shortdata[1] == MIDI_META_EOT)
			ts->status |= ITS_F_ENDOFTRK;
	}
	else
	{
		/* Messages in this range are system messages and aren't
		 * supposed to be in a normal MIDI file. If they are, we
		 * have either misparsed or the authoring software is stupid.
		 */
		return 1;
	}

	/* Event time was already stored as the current track time */
	te->event_time = ts->next_event_time;

	/* Now update to the next event time. The code above MUST properly
	 * maintain the end of track flag in case the end of track meta is
	 * missing.  NOTE: This code is a continuation of the track event
	 * time pre-read which is done at the end of track initialization.
	 */
	if ( !(ts->status & ITS_F_ENDOFTRK))
	{
		DWORD	delta_time;

		if (GetTrackVDWord(ts, &delta_time))
			return 1;

		ts->next_event_time += delta_time;
	}

	return 0;
}
Exemplo n.º 2
0
//
// GetTrackEvent
//
// Fills in the event struct with the next event from the track
//
// pteTemp->tkEvent will contain the absolute tick time of the event
// pteTemp->byShortData[0] will contain
//  MIDI_META if the event is a meta event;
//   in this case pteTemp->byShortData[1] will contain the meta class
//  MIDI_SYSEX or MIDI_SYSEXEND if the event is a SysEx event
//  Otherwise, the event is a channel message and pteTemp->byShortData[1]
//   and pteTemp->byShortData[2] will contain the rest of the event.
//
// pteTemp->dwEventLength will contain
//  The total length of the channel message in pteTemp->byShortData if
//   the event is a channel message
//  The total length of the paramter data pointed to by
//   pteTemp->pLongData otherwise
//
// pteTemp->pLongData will point at any additional paramters if the 
//  event is a SysEx or meta event with non-zero length; else
//  it will contain NULL
//
// Returns FALSE on success or TRUE on any kind of parse error
// Prints its own error message ONLY in the debug version
//
// Maintains the state of the input track (i.e. ptsTrack->dwLeftInBuffer,
// ptsTrack->pTrackPointers, and ptsTrack->byRunningStatus).
//
static BOOL GetTrackEvent( INTRACKSTATE *ptsTrack, PTEMPEVENT pteTemp )
    {
    DWORD   idx;
    BYTE    byByte;
    UINT    dwEventLength;

    // Clear out the temporary event structure to get rid of old data...
    memset( pteTemp, 0, sizeof(TEMPEVENT));

    // Already at end of track? There's nothing to read.
    //
    if(( ptsTrack->fdwTrack & ITS_F_ENDOFTRK )
            || ( !ptsTrack->dwLeftInBuffer && !ptsTrack->dwLeftOnDisk ))
        return( TRUE );

    // Get the first byte, which determines the type of event.
    //
    if( GetTrackByte( ptsTrack, &byByte ))
    return( TRUE );

    // If the high bit is not set, then this is a channel message
    // which uses the status byte from the last channel message
    // we saw. NOTE: We do not clear running status across SysEx or
    // meta events even though the spec says to because there are
    // actually files out there which contain that sequence of data.
    //
    if( !( byByte & 0x80 ))
        {
        // No previous status byte? We're hosed.
        if( !ptsTrack->byRunningStatus )
            {
            TRACKERR(ptsTrack, gteBadRunStat);
            return( TRUE );
            }

        pteTemp->byShortData[0] = ptsTrack->byRunningStatus;
        pteTemp->byShortData[1] = byByte;

        byByte = pteTemp->byShortData[0] & 0xF0;
        pteTemp->dwEventLength = 2;

        // Only program change and channel pressure events are 2 bytes long;
        // the rest are 3 and need another byte
        //
        if(( byByte != MIDI_PRGMCHANGE ) && ( byByte != MIDI_CHANPRESS ))
            {
            if( !ptsTrack->dwLeftInBuffer && !ptsTrack->dwLeftOnDisk )
                {
                TRACKERR( ptsTrack, gteRunStatMsgTrunc );
                ptsTrack->fdwTrack |= ITS_F_ENDOFTRK;
                return( TRUE );
                }

            if( GetTrackByte( ptsTrack, &pteTemp->byShortData[2] ))
        return( TRUE );
            ++pteTemp->dwEventLength;
            }
        }
    else if(( byByte & 0xF0 ) != MIDI_SYSEX )
        {
        // Not running status, not in SysEx range - must be
        // normal channel message (0x80-0xEF)
        //
        pteTemp->byShortData[0] = byByte;
        ptsTrack->byRunningStatus = byByte;
        
        // Strip off channel and just keep message type
        //
        byByte &= 0xF0;

        dwEventLength = ( byByte == MIDI_PRGMCHANGE || byByte == MIDI_CHANPRESS ) ? 1 : 2;
        pteTemp->dwEventLength = dwEventLength + 1;

        if(( ptsTrack->dwLeftInBuffer + ptsTrack->dwLeftOnDisk ) < dwEventLength )
            {
            TRACKERR( ptsTrack, gteChanMsgTrunc );
            ptsTrack->fdwTrack |= ITS_F_ENDOFTRK;
            return( TRUE );
            }

    if( GetTrackByte( ptsTrack, &pteTemp->byShortData[1] ))
        return( TRUE );
        if( dwEventLength == 2 )
            if( GetTrackByte( ptsTrack, &pteTemp->byShortData[2] ))
        return( TRUE );
        } 
    else if(( byByte == MIDI_SYSEX ) || ( byByte == MIDI_SYSEXEND ))
        {
        // One of the SysEx types. (They are the same as far as we're concerned;
        // there is only a semantic difference in how the data would actually
        // get sent when the file is played. We must take care to put the proper
        // event type back on the output track, however.)
        //
        // Parse the general format of:
        //  BYTE    bEvent (MIDI_SYSEX or MIDI_SYSEXEND)
        //  VDWORD  cbParms
        //  BYTE    abParms[cbParms]
        //
        pteTemp->byShortData[0] = byByte;
        if( GetTrackVDWord( ptsTrack, &pteTemp->dwEventLength ))
            {
            TRACKERR( ptsTrack, gteSysExLenTrunc );
            return( TRUE );
            }

        if(( ptsTrack->dwLeftInBuffer + ptsTrack->dwLeftOnDisk )
                                < pteTemp->dwEventLength )
            {
            TRACKERR( ptsTrack, gteSysExTrunc );
            ptsTrack->fdwTrack |= ITS_F_ENDOFTRK;
            return( TRUE );
            }

    // Malloc a temporary memory block to hold the parameter data
    if(( pteTemp->pLongData = malloc( pteTemp->dwEventLength )) == NULL )
        {
        TRACKERR( ptsTrack, gteNoMem );
        return( TRUE );
        }
    // Copy from the input buffer to the parameter data buffer
    for( idx = 0; idx < pteTemp->dwEventLength; idx++ )
        if( GetTrackByte( ptsTrack, pteTemp->pLongData + idx ))
        {
        TRACKERR( ptsTrack, gteSysExTrunc );
        return( TRUE );
        }
    // Increment our counter, which tells the program to look around for
    // a malloc block to free, should it need to exit or reset before the
    // block would normally be freed
    dwMallocBlocks++;
        } 
    else if( byByte == MIDI_META )
        {
        // It's a meta event. Parse the general form:
        //  BYTE    bEvent  (MIDI_META)
        //  BYTE    bClass
        //  VDWORD  cbParms
        //  BYTE    abParms[cbParms]
        //
        pteTemp->byShortData[0] = byByte;

        if( !ptsTrack->dwLeftInBuffer && !ptsTrack->dwLeftOnDisk )
            {
            TRACKERR(ptsTrack, gteMetaNoClass );
            ptsTrack->fdwTrack |= ITS_F_ENDOFTRK;
            return( TRUE );
            }

    if( GetTrackByte( ptsTrack, &pteTemp->byShortData[1] ))
        return( TRUE );

        if( GetTrackVDWord( ptsTrack, &pteTemp->dwEventLength ))
            {   
            TRACKERR( ptsTrack, gteMetaLenTrunc );
            return( TRUE );
            }

        // NOTE: It's perfectly valid to have a meta with no data
        // In this case, dwEventLength == 0 and pLongData == NULL
        //
        if( pteTemp->dwEventLength )
            {       
            if(( ptsTrack->dwLeftInBuffer + ptsTrack->dwLeftOnDisk )
                                    < pteTemp->dwEventLength )
                {
                TRACKERR( ptsTrack, gteMetaTrunc );
                ptsTrack->fdwTrack |= ITS_F_ENDOFTRK;
                return( TRUE );
                }

    // Malloc a temporary memory block to hold the parameter data
        if(( pteTemp->pLongData = malloc( pteTemp->dwEventLength ))
                                        == NULL )
        {
        TRACKERR( ptsTrack, gteNoMem );
        return( TRUE );
        }
    // Copy from the input buffer to the parameter data buffer
        for( idx = 0; idx < pteTemp->dwEventLength; idx++ )
         if( GetTrackByte( ptsTrack, pteTemp->pLongData + idx ))
             {
             TRACKERR( ptsTrack, gteMetaTrunc );
             return( TRUE );
             }
    // Increment our counter, which tells the program to look around for
    // a malloc block to free, should it need to exit or reset before the
    // block would normally be freed
        dwMallocBlocks++;
            }

        if( pteTemp->byShortData[1] == MIDI_META_EOT )
            ptsTrack->fdwTrack |= ITS_F_ENDOFTRK;
        }
    else
        {
        // Messages in this range are system messages and aren't supposed to
        // be in a normal MIDI file. If they are, we've either misparsed or the
        // authoring software is stupid.
        //
        return( TRUE );
        }

    // Event time was already stored as the current track time
    //
    pteTemp->tkEvent = ptsTrack->tkNextEventDue;

    // Now update to the next event time. The code above MUST properly
    // maintain the end of track flag in case the end of track meta is
    // missing.  NOTE: This code is a continuation of the track event
    // time pre-read which is done at the end of track initialization.
    //
    if( !( ptsTrack->fdwTrack & ITS_F_ENDOFTRK ))
        {
        DWORD   tkDelta;

        if( GetTrackVDWord( ptsTrack, &tkDelta ))
            return( TRUE );

        ptsTrack->tkNextEventDue += tkDelta;
        }

    return( FALSE );
    }
Exemplo n.º 3
0
// -------------
// GetTrackEvent
//
// Fills in the event struct with the next event from the track
//
// pMe->tkEvent will contain the absolute tick time of the event
// pMe->abEvent[0] will contain
//  MIDI_META if the event is a meta event;
//   in this case pMe->abEvent[1] will contain the meta class
//  MIDI_SYSEX or MIDI_SYSEXEND if the event is a SysEx event
//  Otherwise, the event is a channel message and pMe->abEvent[1]
//   and pMe->abEvent[2] will contain the rest of the event.
//
// pMe->dwEventLength will contain
//  The total length of the channel message in pMe->abEvent if
//   the event is a channel message
//  The total length of the paramter data pointed to by
//   pMe->pEvent otherwise
//
// pMe->pEvent will point at any additional paramters if the
//  event is a SysEx or meta event with non-zero length; else
//  it will contain NULL
//
// Returns TRUE on success or FALSE on any kind of parse error
// Prints its own error message ONLY in the debug version
//
// Maintains the state of the input track (i.e. pInTrack->iBytesLeft,
// pInTrack->pTrackPointers, and pInTrack->bRunningStatus).
// -------------
static BOOL GetTrackEvent(LPINTRACKSTATE pInTrack, LPTEMPEVENT pMe)
{
	BYTE b;
	UINT32 dwEventLength;

	// Clear out the temporary event structure to get rid of old data...
	ZeroMemory(pMe, sizeof (TEMPEVENT));

	// Already at end of track? There's nothing to read.
	//
	if ((pInTrack->fdwTrack & ITS_F_ENDOFTRK) || !pInTrack->iBytesLeft)
		return FALSE;

	// Get the first BYTE, which determines the type of event.
	//
	b = *pInTrack->pTrackPointer++;
	--pInTrack->iBytesLeft;

	// If the high bit is not set, then this is a channel message
	// which uses the status BYTE from the last channel message
	// we saw. NOTE: We do not clear running status across SysEx or
	// meta events even though the spec says to because there are
	// actually files out there which contain that sequence of data.
	//
	if (!(b & 0x80))
	{
		// No previous status BYTE? We're hosed.
		//
		if (!pInTrack->bRunningStatus)
		{
			TRACKERR(pInTrack, gteBadRunStat);
			return FALSE;
		}

		//faB: the last midi command issued on that track
		pMe->abEvent[0] = pInTrack->bRunningStatus;
		pMe->abEvent[1] = b;        // the data !

		b = (BYTE)(pMe->abEvent[0] & 0xF0);
		pMe->dwEventLength = 2;       //2 data bytes

		// Only program change and channel pressure events are 2 BYTEs long;
		// the rest are 3 and need another BYTE
		//
		if ((b != MIDI_PRGMCHANGE) && (b != MIDI_CHANPRESS))
		{
			if (!pInTrack->iBytesLeft)
			{
				TRACKERR(pInTrack, gteRunStatMsgTrunc);
				pInTrack->fdwTrack |= ITS_F_ENDOFTRK;
				return FALSE;
			}

			pMe->abEvent[2] = *pInTrack->pTrackPointer++;
			--pInTrack->iBytesLeft;
			++pMe->dwEventLength;
		}
	}
	else if ((b & 0xF0) != MIDI_SYSEX)
	{
		// Not running status, not in SysEx range - must be
		// normal channel message (0x80-0xEF)

		pMe->abEvent[0] = b;
		pInTrack->bRunningStatus = b;

		// Strip off channel and just keep message type
		//
		b &= 0xF0;

		dwEventLength = (b == MIDI_PRGMCHANGE || b == MIDI_CHANPRESS) ? 1 : 2;
		pMe->dwEventLength = dwEventLength + 1;

		if (pInTrack->iBytesLeft < dwEventLength)
		{
			TRACKERR(pInTrack, gteChanMsgTrunc);
			pInTrack->fdwTrack |= ITS_F_ENDOFTRK;
			return FALSE;
		}

		pMe->abEvent[1] = *pInTrack->pTrackPointer++;
		if (dwEventLength == 2)
			pMe->abEvent[2] = *pInTrack->pTrackPointer++;

		pInTrack->iBytesLeft -= dwEventLength;
	}
	else if (b == MIDI_SYSEX || b == MIDI_SYSEXEND)
	{
		// One of the SysEx types. (They are the same as far as we're concerned;
		// there is only a semantic difference in how the data would actually
		// get sent when the file is played. We must take care to put the correct
		// event type back on the output track, however.)
		//
		// Parse the general format of:
		//  BYTE        bEvent (MIDI_SYSEX or MIDI_SYSEXEND)
		//  VLONG      cbParms
		//  BYTE        abParms[cbParms]
		//
		pMe->abEvent[0] = b;
		if (!GetTrackVDWord(pInTrack, &pMe->dwEventLength))
		{
			TRACKERR(pInTrack, gteSysExLenTrunc);
			return FALSE;
		}

		if (pInTrack->iBytesLeft < pMe->dwEventLength)
		{
			TRACKERR(pInTrack, gteSysExTrunc);
			pInTrack->fdwTrack |= ITS_F_ENDOFTRK;
			return FALSE;
		}

		pMe->pEvent = pInTrack->pTrackPointer;
		pInTrack->pTrackPointer += pMe->dwEventLength;
		pInTrack->iBytesLeft -= pMe->dwEventLength;
	}
	else if (b == MIDI_META)
	{
		// It's a meta event. Parse the general form:
		//  BYTE        bEvent  (MIDI_META)
		//      BYTE    bClass
		//  VLONG      cbParms
		//      BYTE    abParms[cbParms]
		//
		pMe->abEvent[0] = b;

		if (!pInTrack->iBytesLeft)
		{
			TRACKERR(pInTrack, gteMetaNoClass);
			pInTrack->fdwTrack |= ITS_F_ENDOFTRK;
			return FALSE;
		}

		pMe->abEvent[1] = *pInTrack->pTrackPointer++;
		--pInTrack->iBytesLeft;

		if (!GetTrackVDWord(pInTrack, &pMe->dwEventLength))
		{
			TRACKERR(pInTrack, gteMetaLenTrunc);
			return FALSE;
		}

		// NOTE: Perfectly valid to have a meta with no data
		// In this case, dwEventLength == 0 and pEvent == NULL
		//
		if (pMe->dwEventLength)
		{
			if (pInTrack->iBytesLeft < pMe->dwEventLength)
			{
				TRACKERR(pInTrack, gteMetaTrunc);
				pInTrack->fdwTrack |= ITS_F_ENDOFTRK;
				return FALSE;
			}

			pMe->pEvent = pInTrack->pTrackPointer;
			pInTrack->pTrackPointer += pMe->dwEventLength;
			pInTrack->iBytesLeft -= pMe->dwEventLength;
		}

		if (pMe->abEvent[1] == MIDI_META_EOT)
			pInTrack->fdwTrack |= ITS_F_ENDOFTRK;
	}
	else
	{
		// Messages in this range are system messages and aren't supposed to
		// be in a normal MIDI file. If they are, we've misparsed or the
		// authoring software is stpuid.
#ifdef DEBUGMIDISTREAM
		I_OutputMsg("System message not supposed to be in MIDI file..\n");
#endif
		return FALSE;
	}

	// Event time was already stored as the current track time
	//
	pMe->tkEvent = pInTrack->tkNextEventDue;

	// Now update to the next event time. The code above MUST properly
	// maintain the end of track flag in case the end of track meta is
	// missing.

	if (!(pInTrack->fdwTrack & ITS_F_ENDOFTRK))
	{
		DWORD tkDelta;

		if (!GetTrackVDWord(pInTrack, &tkDelta))
			return FALSE;

		pInTrack->tkNextEventDue += tkDelta;
	}

	return TRUE;
}