示例#1
0
//
// GetTrackVDWord
//
// Attempts to parse a variable length DWORD from the given track. A VDWord
// in a MIDI file
//  (a) is in lo-hi format 
//  (b) has the high bit set on every byte except the last
//
// Returns the DWORD in *lpdw and TRUE on success; else
// FALSE if we hit end of track first. Sets ITS_F_ENDOFTRK
// if we hit end of track.
//
static BOOL GetTrackVDWord( PINTRACKSTATE ptsTrack, LPDWORD lpdw )
    {
    BYTE    byByte;
    DWORD   dw = 0;

    if( ptsTrack->fdwTrack & ITS_F_ENDOFTRK )
        return( TRUE );

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

        if( GetTrackByte( ptsTrack, &byByte ))
        return( TRUE );

        dw = ( dw << 7 ) | ( byByte & 0x7F );
        } while( byByte & 0x80 );

    *lpdw = dw;

    return( FALSE );
    }
示例#2
0
/* GetTrackVDWord
 *
 * Parse a variable length DWORD from the given track. A VDWord in
 * a MIDI file is in lo-hi format and has the high bit set on every
 * byte except the last.
 *
 * Returns the DWORD in *v and zero on success; else non-zero if we
 * hit end of track. Sets ITS_F_ENDOFTRK if we hit end of track.
 */
static int GetTrackVDWord (track_state_t *ts, DWORD *v)
{
	BYTE	b;
	DWORD	val = 0;

	if (ts->status & ITS_F_ENDOFTRK)
		return 1;

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

		if (GetTrackByte(ts, &b))
			return 1;

		val = (val << 7) | (b & 0x7F);
	} while (b & 0x80);

	*v = val;

	return 0;
}
示例#3
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 );
    }
示例#4
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;
}