Пример #1
0
// -------------------------
// Mid2StreamRewindConverter
// This little function is an adaptation of the ConverterInit() code which
// resets the tracks without closing and opening the file, thus reducing the
// time it takes to loop back to the beginning when looping.
// -------------------------
static BOOL Mid2StreamRewindConverter(VOID)
{
	DWORD          iTrack;
	LPINTRACKSTATE pInTrack;

	tkCurrentTime = 0;

	// reset to start of midi file
	ifs.iBytesLeft = ifs.FileSize;
	ifs.pFilePointer = ifs.pFile;

	for (iTrack = 0, pInTrack = ifs.pTracks; iTrack < ifs.nTracks; ++iTrack, ++pInTrack)
	{
		pInTrack->iBytesLeft = pInTrack->iTrackLen;

		// Setup pointer to the current position in the track
		pInTrack->pTrackPointer = pInTrack->pTrackData;

		pInTrack->fdwTrack = 0;
		pInTrack->bRunningStatus = BAD_MIDI_FIX;
		pInTrack->tkNextEventDue = 0;

		// Handle bozo MIDI files which contain empty track chunks
		if (!pInTrack->iBytesLeft)
		{
			pInTrack->fdwTrack |= ITS_F_ENDOFTRK;
			continue;
		}

		// We always preread the time from each track so the mixer code can
		// determine which track has the next event with a minimum of work
		if (!GetTrackVDWord(pInTrack, &pInTrack->tkNextEventDue))
		{
			I_OutputMsg("Read error while reading first delta time of track.\n");
			return TRUE;
		}
	}
	// End of track initialization code

	return FALSE;
}
Пример #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 );
    }
Пример #3
0
static BOOL RewindConverter( void )
    {
    DWORD   dwToRead, cbRead, idx;
    BOOL    fRet;

    PINTRACKSTATE   ptsTrack;

    tkCurrentTime = 0;

    for( idx = 0, ptsTrack = ifs.pitsTracks; idx < ifs.dwTrackCount;
                                ++idx, ++ptsTrack )
    {
///////////////////////////////////////////////////////////////////////////////
// Here we need to determine if all track data will fit into a single one of
// our track buffers.  If not, we need to read in a buffer full and come back
// for more later, saving the file offset to continue from and the amount left
// to read in the track structure.

//    SetFilePointer( hInFile, ptsTrack->foTrackStart, NULL, FILE_BEGIN );
    SetFilePointer2( ptsTrack->foTrackStart, NULL, FILE_BEGIN );

    if( ptsTrack->dwTrackLength > TRACK_BUFFER_SIZE )
        dwToRead = TRACK_BUFFER_SIZE;
    else
        dwToRead = ptsTrack->dwTrackLength;
/*    if( !ReadFile( hInFile, ptsTrack->pTrackStart, dwToRead, &cbRead, NULL )
        || ( cbRead != dwToRead ))
        {
        MessageBox( GetActiveWindow(), szInitErrInFile,
                "TEST", MB_OK | MB_ICONEXCLAMATION );
        goto Rewind_Cleanup;
        }*/
    if( !ReadFile2( ptsTrack->pTrackStart, dwToRead, &cbRead, NULL )
        || ( cbRead != dwToRead ))
        {
		     Con_Printf("MIDI: %s\n", szInitErrInFile);
        goto Rewind_Cleanup;
        }
    // Save the number of bytes that didn't make it into the buffer
    ptsTrack->dwLeftOnDisk = ptsTrack->dwTrackLength - cbRead;
    ptsTrack->dwLeftInBuffer = cbRead;
    // Save the current file offset so we can seek to it later
/*    ptsTrack->foNextReadStart = SetFilePointer( hInFile, 0,
                            NULL, FILE_CURRENT );*/
    ptsTrack->foNextReadStart = SetFilePointer2( 0,
                            NULL, FILE_CURRENT );

        // Setup pointer to the current position in the track
        ptsTrack->pTrackCurrent = ptsTrack->pTrackStart;
        ptsTrack->fdwTrack = 0;
        ptsTrack->byRunningStatus = 0;
        ptsTrack->tkNextEventDue = 0;


        // Handle bozo MIDI files which contain empty track chunks
        //
        if( !ptsTrack->dwLeftInBuffer && !ptsTrack->dwLeftOnDisk )
            {
            ptsTrack->fdwTrack |= ITS_F_ENDOFTRK;
            continue;
            }

        // We always preread the time from each track so the mixer code can
        // determine which track has the next event with a minimum of work
        //
        if( GetTrackVDWord( ptsTrack, &ptsTrack->tkNextEventDue ))
            {
					Con_Printf("MIDI: %s\n", szInitErrInFile);
            goto Rewind_Cleanup;
            }
    // Step over any unread data, advancing to the beginning of the next
    // track's data
/*    SetFilePointer( hInFile, ptsTrack->foTrackStart + ptsTrack->dwTrackLength,
            NULL, FILE_BEGIN );*/
    SetFilePointer2( ptsTrack->foTrackStart + ptsTrack->dwTrackLength,
            NULL, FILE_BEGIN );
        }   // End of track initialization code

    fRet = FALSE;

    Rewind_Cleanup:

    if( fRet )
    return( TRUE );

    return( FALSE );
    }
Пример #4
0
// ConverterInit
// 
// Open the input file
// Allocate and read the entire input file into memory
// Validate the input file structure
// Allocate the input track structures and initialize them
// Initialize the output track structures
//
// Return TRUE on success
// Prints its own error message if something goes wrong
//
BOOL ConverterInit( LPSTR szInFile )
    {
    BOOL        fRet = TRUE;
    DWORD       cbRead, dwTag, cbHeader, dwToRead;
    MIDIFILEHDR     Header;
    PINTRACKSTATE   ptsTrack;
    UINT        idx;

    tkCurrentTime = 0;

    // Initialize things we'll try to free later if we fail
    //
    memset( &ifs, 0, sizeof(INFILESTATE));
    ifs.cbFileLength = 0;
    ifs.pitsTracks = NULL;

    // Attempt to open the input and output files
    //
	MidiData = (byte *)COM_LoadHunkFile2((char *)szInFile, (int *)&ifs.cbFileLength);
	if (!MidiData) 
	{
		goto Init_Cleanup;
	}
	MidiOffset = 0;
	MidiSize = ifs.cbFileLength;

/*    hInFile = CreateFile( szInFile, GENERIC_READ,
            FILE_SHARE_READ, NULL, OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL, NULL);
    if( hInFile == INVALID_HANDLE_VALUE )
    {
    wsprintf( szTemp, "Could not open \"%s\" for read.\n", szInFile );
    MessageBox( GetActiveWindow(), szTemp,
            "TEST", MB_OK | MB_ICONEXCLAMATION );
    goto Init_Cleanup;
    }
	*/

// Figure out how big the input file is.
/*    if((( ifs.cbFileLength = GetFileSize( hInFile, NULL )) == (UINT)-1 ))
    {
    MessageBox( GetActiveWindow(), "File system error on input file.\n",
                "TEST", MB_OK | MB_ICONEXCLAMATION );
    goto Init_Cleanup;
    }*/

// Set up to read from the memory buffer. Read and validate
// - MThd header
// - size of file header chunk
// - file header itself
//  
    if( GetInFileData( &dwTag, sizeof(DWORD))
        || ( dwTag != MThd )
        || GetInFileData( &cbHeader, sizeof(DWORD))
        || (( cbHeader = DWORDSWAP( cbHeader )) < sizeof(MIDIFILEHDR))
            || GetInFileData( &Header, cbHeader ) )
        {
		     Con_Printf("MIDI: %s\n",szInitErrInFile);
	        goto Init_Cleanup;
        }

// File header is stored in hi-lo order. Swap this into Intel order and save
// parameters in our native int size (32 bits)
//
    ifs.dwFormat = (DWORD)WORDSWAP( Header.wFormat );
    ifs.dwTrackCount = (DWORD)WORDSWAP( Header.wTrackCount );
    ifs.dwTimeDivision = (DWORD)WORDSWAP( Header.wTimeDivision );

// We know how many tracks there are; allocate the structures for them and parse
// them. The parse merely looks at the MTrk signature and track chunk length
// in order to skip to the next track header.
//
    ifs.pitsTracks = (PINTRACKSTATE)GlobalAllocPtr( GPTR,
                    ifs.dwTrackCount * sizeof(INTRACKSTATE));
    if( ifs.pitsTracks == NULL )
        {
		     Con_Printf("MIDI: %s\n",szInitErrMem);
        goto Init_Cleanup;
        }

    for( idx = 0, ptsTrack = ifs.pitsTracks; idx < ifs.dwTrackCount;
                                ++idx, ++ptsTrack )
    {
    if(( ptsTrack->pTrackStart
            = GlobalAllocPtr( GHND, TRACK_BUFFER_SIZE )) == NULL )
        {
		     Con_Printf("MIDI: %s\n", szNoTrackBuffMem);
        goto Init_Cleanup;
        }

    if( GetInFileData( &dwTag, sizeof(dwTag)) || ( dwTag != MTrk )
            || GetInFileData( &cbHeader, sizeof(cbHeader)))
        {
		     Con_Printf("MIDI: %s\n", szInitErrInFile);
        goto Init_Cleanup;
        }

    cbHeader = DWORDSWAP( cbHeader );
    ptsTrack->dwTrackLength = cbHeader; // Total track length
///////////////////////////////////////////////////////////////////////////////
// Here we need to determine if all track data will fit into a single one of
// our track buffers.  If not, we need to read in a buffer full and come back
// for more later, saving the file offset to continue from and the amount left
// to read in the track structure.

    // Save the file offset of the beginning of this track
/*    ptsTrack->foTrackStart = SetFilePointer( hInFile, 0, NULL,
                        FILE_CURRENT );*/
    ptsTrack->foTrackStart = SetFilePointer2( 0, NULL,
                        FILE_CURRENT );

    if( ptsTrack->dwTrackLength > TRACK_BUFFER_SIZE )
        dwToRead = TRACK_BUFFER_SIZE;
    else
        dwToRead = ptsTrack->dwTrackLength;
/*    if( !ReadFile( hInFile, ptsTrack->pTrackStart, dwToRead, &cbRead, NULL )
        || ( cbRead != dwToRead ))
        {
        MessageBox( GetActiveWindow(), szInitErrInFile,
                "TEST", MB_OK | MB_ICONEXCLAMATION );
        goto Init_Cleanup;
        }*/
    if( !ReadFile2( ptsTrack->pTrackStart, dwToRead, &cbRead, NULL )
        || ( cbRead != dwToRead ))
        {
		     Con_Printf("MIDI: %s\n", szInitErrInFile);
        goto Init_Cleanup;
        }
    // Save the number of bytes that didn't make it into the buffer
    ptsTrack->dwLeftOnDisk = ptsTrack->dwTrackLength - cbRead;
    ptsTrack->dwLeftInBuffer = cbRead;
    // Save the current file offset so we can seek to it later
/*    ptsTrack->foNextReadStart = SetFilePointer( hInFile, 0,
                            NULL, FILE_CURRENT );*/
    ptsTrack->foNextReadStart = SetFilePointer2( 0,
                            NULL, FILE_CURRENT );

        // Setup pointer to the current position in the track
        ptsTrack->pTrackCurrent = ptsTrack->pTrackStart;
        ptsTrack->fdwTrack = 0;
        ptsTrack->byRunningStatus = 0;
        ptsTrack->tkNextEventDue = 0;

        // Handle bozo MIDI files which contain empty track chunks
        //
        if( !ptsTrack->dwLeftInBuffer && !ptsTrack->dwLeftOnDisk )
            {
            ptsTrack->fdwTrack |= ITS_F_ENDOFTRK;
            continue;
            }

        // We always preread the time from each track so the mixer code can
        // determine which track has the next event with a minimum of work
        //
        if( GetTrackVDWord( ptsTrack, &ptsTrack->tkNextEventDue ))
            {
				  Con_Printf("MIDI: %s\n", szInitErrInFile);
            goto Init_Cleanup;
            }
    // Step over any unread data, advancing to the beginning of the next
    // track's data
/*    SetFilePointer( hInFile, ptsTrack->foTrackStart + ptsTrack->dwTrackLength,
            NULL, FILE_BEGIN );*/
    SetFilePointer2( ptsTrack->foTrackStart + ptsTrack->dwTrackLength,
            NULL, FILE_BEGIN );
            
        }   // End of track initialization code

    fRet = FALSE;
    
    Init_Cleanup:
    if( fRet )
        ConverterCleanup();

    return( fRet );
    }
Пример #5
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;
}
Пример #6
0
/* RewindConverter
 *
 * An adaptation of the ConverterInit() code which resets the
 * tracks without closing and opening the file.
 */
static int RewindConverter (void)
{
	DWORD	bytes_wanted, bytes_read, idx;
	int	err = 1;
	track_state_t	*ts;

	currenttime = 0;

	for (idx = 0, ts = mfs.tracks; idx < mfs.numtracks; ++idx, ++ts)
	{
/* Determine whether all track data will fit into a single one of our track
 * buffers. If not, we need to read in a buffer full and come back for more
 * later, saving the file offset to continue from and the amount left to read
 * in the track structure. */

		MID2STREAM_seek(ts->start_ofs, SEEK_SET);

		if (ts->length > TRACK_BUFFER_SIZE)
			bytes_wanted = TRACK_BUFFER_SIZE;
		else
			bytes_wanted = ts->length;

		MID2STREAM_readfile(ts->start_ptr, bytes_wanted, &bytes_read);
		if (bytes_read != bytes_wanted)
			goto Rewind_Cleanup;

		/* Save the number of bytes that didn't make it into the buffer */
		ts->left_on_disk = ts->length - bytes_read;
		ts->left_in_buffer = bytes_read;

		/* Save the current file offset so we can seek to it later */
		ts->nextread_ofs = MID2STREAM_seek(0, SEEK_CUR);

		/* Setup pointer to the current position in the track */
		ts->current_ptr = ts->start_ptr;
		ts->status = 0;
		ts->running_status = 0;
		ts->next_event_time = 0;

		/* Handle bozo MIDI files which contain empty track chunks */
		if (!ts->left_in_buffer && !ts->left_on_disk)
		{
			ts->status |= ITS_F_ENDOFTRK;
			continue;
		}

		/* always preread the time from each track so the mixer code can
		 * determine which track has the next event with minimum work. */
		if (GetTrackVDWord(ts, &ts->next_event_time))
			goto Rewind_Cleanup;

		/* Step over any unread data, advancing to the beginning of the next
		 * track's data */
		MID2STREAM_seek(ts->start_ofs + ts->length, SEEK_SET);

	}	/* End of track initialization code */

	err = 0;

Rewind_Cleanup:
	if (err)
		Con_Printf("MIDI: %s\n", err_bad_midi_file);

	return err;
}
Пример #7
0
/* ConverterInit
 *
 * Open the input file
 * Allocate and read the entire input file into memory
 * Validate the input file structure
 * Allocate the input track structures and initialize them
 * Initialize the output track structures
 *
 * Return zero on success
 */
int ConverterInit (const char *filename)
{
	int	err = 1;
	DWORD	bytes_wanted, bytes_read, magic, bytes;
	UINT	idx;
	midihdr_t	header;
	track_state_t	*ts;

	currenttime = 0;

	memset (&mfs, 0, sizeof(midi_filestate_t));
	memset (&midi_fh, 0, sizeof(fshandle_t));

	if (MID2STREAM_fileopen(filename) != 0)
		return 1;

	mfs.length = midi_fh.length;

/* Read and validate MThd header, size of file header chunk
 * and the file header itself.  */
	if (GetInFileData(&magic, sizeof(DWORD)))
		goto Init_Cleanup;
	magic = (DWORD)BigLong(magic);
	if (magic == MIDI_MAGIC_RIFF) /* RMID ?? */
	{
		if (GetInFileData(&bytes, sizeof(DWORD)) != 0 || /* size */
		    GetInFileData(&magic, sizeof(DWORD)) != 0 ||
		    MIDI_MAGIC_RMID != (DWORD)BigLong(magic)  ||
		    GetInFileData(&magic, sizeof(DWORD)) != 0 ||
	/* "data" */0x64617461 != (DWORD)BigLong(magic) ||
		    GetInFileData(&bytes, sizeof(DWORD)) != 0 || /* size */
		    /* SMF must begin from here onwards: */
		    GetInFileData(&magic, sizeof(DWORD)) != 0) {
			goto Init_Cleanup;
		}
		magic = (DWORD)BigLong(magic);
	}
	if (magic != MIDI_MAGIC_MTHD)
		goto Init_Cleanup;
	if (GetInFileData(&bytes, sizeof(DWORD)))
		goto Init_Cleanup;
	if ((bytes = (DWORD)BigLong(bytes)) < sizeof(midihdr_t))
		goto Init_Cleanup;
	if (GetInFileData(&header, bytes))
		goto Init_Cleanup;

/* File header is stored in big endian (hi-lo) order. */
	mfs.format	= (DWORD) BigShort(header.format);
	mfs.numtracks	= (DWORD) BigShort(header.numtracks);
	mfs.timediv	= (DWORD) BigShort(header.timediv);

	if (mfs.format != 0 && mfs.format != 1) /* Type-2 not supported */
		goto Init_Cleanup;
	if (mfs.numtracks == 0)
		goto Init_Cleanup;
	if (mfs.format == 0 && mfs.numtracks != 1)
		goto Init_Cleanup;

/* We know how many tracks there are; allocate structures for them
 * and parse them. The parse merely looks at the MTrk signature and
 * track chunk length in order to skip to the next track header. */
	mfs.tracks = (track_state_t *) Z_Malloc(mfs.numtracks * sizeof(track_state_t), Z_MAINZONE);
	for (idx = 0, ts = mfs.tracks; idx < mfs.numtracks; ++idx, ++ts)
	{
		ts->start_ptr = (BYTE *) Z_Malloc(TRACK_BUFFER_SIZE, Z_MAINZONE);
		if (GetInFileData(&magic, sizeof(magic)))
			goto Init_Cleanup;
		if ((magic = (DWORD)BigLong(magic)) != MIDI_MAGIC_MTRK)
			goto Init_Cleanup;
		if (GetInFileData(&bytes, sizeof(bytes)))
			goto Init_Cleanup;

		bytes = (DWORD)BigLong(bytes);
		ts->length = bytes; /* Total track length */

/* Determine whether all track data will fit into a single one of our track
 * buffers. If not, we need to read in a buffer full and come back for more
 * later, saving the file offset to continue from and the amount left to read
 * in the track structure. */

		/* Save the file offset of the beginning of this track */
		ts->start_ofs = MID2STREAM_seek(0, SEEK_CUR);

		if (ts->length > TRACK_BUFFER_SIZE)
			bytes_wanted = TRACK_BUFFER_SIZE;
		else
			bytes_wanted = ts->length;

		MID2STREAM_readfile(ts->start_ptr, bytes_wanted, &bytes_read);
		if (bytes_read != bytes_wanted)
			goto Init_Cleanup;

		/* Save the number of bytes that didn't make it into the buffer */
		ts->left_on_disk = ts->length - bytes_read;
		ts->left_in_buffer = bytes_read;

		/* Save the current file offset so we can seek to it later */
		ts->nextread_ofs = MID2STREAM_seek(0, SEEK_CUR);

		/* Setup pointer to the current position in the track */
		ts->current_ptr = ts->start_ptr;
		ts->status = 0;
		ts->running_status = 0;
		ts->next_event_time = 0;

		/* Handle bozo MIDI files which contain empty track chunks */
		if (!ts->left_in_buffer && !ts->left_on_disk)
		{
			ts->status |= ITS_F_ENDOFTRK;
			continue;
		}

		/* always preread the time from each track so the mixer code can
		 * determine which track has the next event with minimum work. */
		if (GetTrackVDWord(ts, &ts->next_event_time))
			goto Init_Cleanup;

		/* Step over any unread data, advancing to the beginning of the next
		 * track's data */
		MID2STREAM_seek(ts->start_ofs + ts->length, SEEK_SET);

	}	/* End of track initialization code */

	err = 0;

Init_Cleanup:
	if (err)
	{
		Con_Printf("MIDI: %s\n", err_bad_midi_file);
		ConverterCleanup();
	}

	return err;
}
Пример #8
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;
}
Пример #9
0
// ----
// Init (stand-alone version)
//
// Open the input and output files
// Allocate and read the entire input file into memory
// Validate the input file structure
// Allocate the input track structures and initialize them
// Initialize the output track structures
//
// Return TRUE on success
// Prints its own error message if something goes wrong
//
// ----
static BOOL Init(LPSTR szInFile, LPSTR szOutFile)
{
	BOOL            fRet = FALSE;
	LONG            cbRead;
	UINT32          *pChunkID;
	UINT32          *pChunkSize;
	LONG            iChunkSize;
	LPMIDIFILEHDR   pHeader;
	LPINTRACKSTATE  pInTrack;
	UINT            iTrack;

	// Initialize things we'll try to free later if we fail
	//
	ifs.FileSize = 0;
	ifs.pFile = NULL;
	//ifs.pTracks = NULL;

	// Attempt to open the input and output files
	//
	hInFile = CreateFileA(szInFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if (INVALID_HANDLE_VALUE == hInFile)
	{
		I_OutputMsg("Could not open \"%s\" for read.\n", szInFile);
		goto Init_Cleanup;
	}

	hOutFile = CreateFileA(szOutFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (INVALID_HANDLE_VALUE == hOutFile)
	{
		I_OutputMsg("Could not open \"%s\" for write.\n", szOutFile);
		goto Init_Cleanup;
	}

	// Figure out how big the input file is and allocate a chunk of memory big enough
	// to hold the whole thing. Read the whole file in at once.
	//
	if (INVALID_FILE_SIZE == (ifs.FileSize = GetFileSize(hInFile, NULL)))
	{
		I_OutputMsg("File system error on input file.\n");
		goto Init_Cleanup;
	}

	if (NULL == (ifs.pFile = GlobalAllocPtr(GPTR, ifs.FileSize)))
	{
		I_OutputMsg("Out of memory.\n");
		goto Init_Cleanup;
	}

	if ((!ReadFile(hInFile, ifs.pFile, ifs.FileSize, &cbRead, NULL)) ||
		cbRead != ifs.FileSize)
	{
		I_OutputMsg("Read error on input file.\n");
		goto Init_Cleanup;
	}

	// Set up to read from the memory buffer. Read and validate
	// - MThd header
	// - size of file header chunk
	// - file header itself
	//
	ifs.iBytesLeft = ifs.FileSize;
	ifs.pFilePointer = ifs.pFile;

	// note: midi header size should always be 6
	if ((pChunkID = (UINT32*)GetInFileData(sizeof (*pChunkID))) == NULL ||
		*pChunkID != MThd ||
		(pChunkSize = (UINT32*)GetInFileData(sizeof (*pChunkSize))) == NULL ||
		(iChunkSize = LONGSWAP(*pChunkSize)) < sizeof (MIDIFILEHDR) ||
		(pHeader = (LPMIDIFILEHDR)GetInFileData(iChunkSize)) == NULL)
	{
		I_OutputMsg("Read error on MIDI header.\n");
		goto Init_Cleanup;
	}

	// File header is stored in hi-lo order. Swap this into Intel order and save
	// parameters in our native int size (32 bits)
	//
	ifs.dwFormat = (LONG)WORDSWAP(pHeader->wFormat);
	ifs.nTracks   = (LONG)WORDSWAP(pHeader->nTracks);
	ifs.dwTimeDivision = (LONG)WORDSWAP(pHeader->wTimeDivision);

#ifdef DEBUGMIDISTREAM
	I_OutputMsg("MIDI Header:\n"
	            "------------\n"
	            "format: %d\n"
	            "number of tracks: %d\n"
	            "time division: %d\n", ifs.dwFormat, ifs.nTracks, ifs.dwTimeDivision);
#endif

	// We know how many tracks there are; allocate the structures for them and parse
	// them. The parse merely looks at the MTrk signature and track chunk length
	// in order to skip to the next track header.
	// faB: now static
	// ifs.pTracks = (INTRACKSTATE *)GlobalAllocPtr(GPTR, ifs.nTracks*sizeof (INTRACKSTATE));
	// if (ifs.pTracks == NULL)
	// {
	//    I_OutputMsg("Out of memory.\n");
	//    goto Init_Cleanup;
	// }

	// faB: made it static, but don't quit if there are more tracks, just skip'em
	// (this isn't really a limit, since 32 tracks are really the maximum for MIDI files)
	if (ifs.nTracks > MAX_MIDI_IN_TRACKS)
		ifs.nTracks = MAX_MIDI_IN_TRACKS;

	for (iTrack = 0, pInTrack = ifs.pTracks; iTrack < ifs.nTracks; ++iTrack, ++pInTrack)
	{
		if ((pChunkID = (UINT32*)GetInFileData(sizeof (*pChunkID))) == NULL ||
			*pChunkID!= MTrk ||
			(pChunkSize = (UINT32*)GetInFileData(sizeof (*pChunkSize))) == NULL)
		{
			I_OutputMsg("Read error on track header.\n");
			goto Init_Cleanup;
		}

		iChunkSize = LONGSWAP(*pChunkSize);
		pInTrack->iTrackLen = iChunkSize;
		pInTrack->iBytesLeft = iChunkSize;
		pInTrack->pTrackData = GetInFileData(iChunkSize);
		if (pInTrack->pTrackData == NULL)
		{
			I_OutputMsg("Read error while reading track data.\n");
			goto Init_Cleanup;
		}

#ifdef DEBUGMIDISTREAM
		I_OutputMsg("Track %d : length %d bytes\n", iTrack, iChunkSize);
		pInTrack->nTrack = iTrack;
#endif
		pInTrack->pTrackPointer = pInTrack->pTrackData;
		pInTrack->fdwTrack = 0;
		pInTrack->bRunningStatus = 0;

		// Handle bozo MIDI files which contain empty track chunks
		//
		if (!pInTrack->iBytesLeft)
		{
			pInTrack->fdwTrack |= ITS_F_ENDOFTRK;
			continue;
		}

		// We always preread the time from each track so the mixer code can
		// determine which track has the next event with a minimum of work
		//
		if (!GetTrackVDWord(pInTrack, &pInTrack->tkNextEventDue))
		{
			I_OutputMsg("Read error while reading first delta time of track.\n");
			goto Init_Cleanup;
		}
	}

	ots.tkTrack = 0;
	ots.pFirst = NULL;
	ots.pLast = NULL;

	fRet = TRUE;

Init_Cleanup:
	if (!fRet)
		Cleanup();

	return fRet;
}
Пример #10
0
// -----------------------
// Mid2StreamConverterInit
//
// Validate the input file structure
// Allocate the input track structures and initialize them (faB: now STATIC)
// Initialize the output track structures
//
// Return TRUE on success
// -----------------------
BOOL Mid2StreamConverterInit(LPBYTE pMidiData, size_t iMidiSize)
{
	BOOL           fRet = TRUE;
	UINT32         *pChunkID;
	UINT32         *pChunkSize;
	UINT32          iChunkSize;
	LPMIDIFILEHDR  pHeader;
	LPINTRACKSTATE pInTrack;
	UINT           iTrack;

	tkCurrentTime = 0;

	// Initialize things we'll try to free later if we fail
	ZeroMemory(&ifs, sizeof (INFILESTATE));
	//ifs.pTracks = NULL;   //faB: now static

	// Set up to read from the memory buffer. Read and validate
	// - MThd header
	// - size of file header chunk
	// - file header itself
	//
	ifs.FileSize = iMidiSize;
	ifs.pFile = pMidiData;
	ifs.iBytesLeft = ifs.FileSize;
	ifs.pFilePointer = ifs.pFile;

#ifdef DEBUGMIDISTREAM
	I_OutputMsg("Midi file size: %d\n", iMidiSize);
#endif

	// note: midi header size should always be 6
	if ((pChunkID = (UINT32*)GetInFileData(sizeof (*pChunkID))) == NULL ||
		*pChunkID != MThd ||
		(pChunkSize = (UINT32*)GetInFileData(sizeof (*pChunkSize))) == NULL ||
		(iChunkSize = LONGSWAP(*pChunkSize)) < sizeof (MIDIFILEHDR) ||
		(pHeader = (LPMIDIFILEHDR)GetInFileData(iChunkSize)) == NULL)
	{
		I_OutputMsg("Read error on MIDI header.\n");
		goto Init_Cleanup;
	}

	ifs.dwFormat = (LONG)WORDSWAP(pHeader->wFormat);
	ifs.nTracks   = (LONG)WORDSWAP(pHeader->nTracks);
	ifs.dwTimeDivision = (LONG)WORDSWAP(pHeader->wTimeDivision);

#ifdef DEBUGMIDISTREAM
	I_OutputMsg("MIDI Header:\n"
				"------------\n"
				"format: %d\n"
				"number of tracks: %d\n"
				"time division: %d\n", ifs.dwFormat, ifs.nTracks, ifs.dwTimeDivision);
#endif

	/* faB: made static
	ifs.pTracks = (INTRACKSTATE *)GlobalAllocPtr(GPTR, ifs.nTracks*sizeof (INTRACKSTATE));
	if (ifs.pTracks == NULL)
	{
		I_OutputMsg("Out of memory.\n");
		goto Init_Cleanup;
	}
	*/

	// faB: made it static, but don't quit if there are more tracks, just skip'em
	if (ifs.nTracks > MAX_MIDI_IN_TRACKS)
		ifs.nTracks = MAX_MIDI_IN_TRACKS;

	for (iTrack = 0, pInTrack = ifs.pTracks; iTrack < ifs.nTracks; ++iTrack, ++pInTrack)
	{
		if ((pChunkID = (UINT32*)GetInFileData(sizeof (*pChunkID))) == NULL ||
			*pChunkID!= MTrk ||
			(pChunkSize = (UINT32*)GetInFileData(sizeof (*pChunkSize))) == NULL)
		{
			I_OutputMsg("Read error on track header.\n");
			goto Init_Cleanup;
		}

		iChunkSize = LONGSWAP(*pChunkSize);
		pInTrack->iTrackLen = iChunkSize;       // Total track length
		pInTrack->iBytesLeft = iChunkSize;
		pInTrack->pTrackData = GetInFileData(iChunkSize);
		if (pInTrack->pTrackData == NULL)
		{
			I_OutputMsg("Read error while reading track data.\n");
			goto Init_Cleanup;
		}

#ifdef DEBUGMIDISTREAM
		I_OutputMsg("Track %d : length %d bytes\n", iTrack, iChunkSize);
		pInTrack->nTrack = iTrack;
#endif
		// Setup pointer to the current position in the track
		pInTrack->pTrackPointer = pInTrack->pTrackData;

		pInTrack->fdwTrack = 0;
		pInTrack->bRunningStatus = BAD_MIDI_FIX;
		pInTrack->tkNextEventDue = 0;

		// Handle bozo MIDI files which contain empty track chunks
		if (!pInTrack->iBytesLeft)
		{
			pInTrack->fdwTrack |= ITS_F_ENDOFTRK;
			continue;
		}

		// We always preread the time from each track so the mixer code can
		// determine which track has the next event with a minimum of work
		if (!GetTrackVDWord(pInTrack, &pInTrack->tkNextEventDue))
		{
			I_OutputMsg("Read error while reading first delta time of track.\n");
			goto Init_Cleanup;
		}
	}
	// End of track initialization code

	fRet = FALSE;

Init_Cleanup:
	if (fRet)
		Mid2StreamConverterCleanup();

	return fRet;
}