⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mid2strm.c

📁 The source code of Doom legacy for windows
💻 C
📖 第 1 页 / 共 4 页
字号:
#endif

    /* faB: made static
    ifs.pTracks = (INTRACKSTATE*)GlobalAllocPtr(GPTR, ifs.nTracks*sizeof(INTRACKSTATE));
    if (ifs.pTracks==NULL)
    {
        CONS_Printf ( "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 = (ULONG*)GetInFileData(sizeof(*pChunkID))) == NULL ||
            *pChunkID!= MTrk ||
            (pChunkSize = (ULONG*)GetInFileData(sizeof(*pChunkSize))) == NULL)
        {
            CONS_Printf ( "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)
        {
            CONS_Printf ( "Read error while reading track data.\n");
            goto Init_Cleanup;
        }

#ifdef DEBUGMIDISTREAM
        CONS_Printf ("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))
        {
            CONS_Printf ( "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 );
}


// ----------------------
// AddEventToStreamBuffer
//
// Put the given event into the given stream buffer at the given location
// pMe must point to an event filled out in accordance with the
// description given in GetTrackEvent
//
// Returns FALSE on sucess or TRUE on an error condition
// Handles its own error notification by displaying to the appropriate
// output device (either our debugging window, or the screen).
// ----------------------
static int AddEventToStreamBuffer( PTEMPEVENT pMe, CONVERTINFO *lpciInfo )
{
    DWORD       tkNow, tkDelta;
    MIDIEVENT   *pmeEvent;

    pmeEvent = (MIDIEVENT *)( lpciInfo->mhBuffer.lpData
                                                + lpciInfo->dwStartOffset
                                                + lpciInfo->dwBytesRecorded );

    // When we see a new, empty buffer, set the start time on it...
    if( !lpciInfo->dwBytesRecorded )
        lpciInfo->tkStart = tkCurrentTime;

    // Use the above set start time to figure out how much longer we should fill
    // this buffer before officially declaring it as "full"
    if( tkCurrentTime - lpciInfo->tkStart > dwBufferTickLength )
    {
        if( lpciInfo->bTimesUp )
        {
            lpciInfo->bTimesUp = FALSE;
            return( CONVERTERR_BUFFERFULL );
        }
        else
            lpciInfo->bTimesUp = TRUE;
    }

    tkNow = tkCurrentTime;

    // Delta time is absolute event time minus absolute time
    // already gone by on this track
    tkDelta = pMe->tkEvent - tkCurrentTime;

    // Event time is now current time on this track
    tkCurrentTime = pMe->tkEvent;

    if( pMe->abEvent[0] < MIDI_SYSEX )
    {
        // Channel message. We know how long it is, just copy it.
        // Need 3 DWORD's: delta-t, stream-ID, event
        if( lpciInfo->dwMaxLength-lpciInfo->dwBytesRecorded < 3*sizeof(DWORD))
        {
            // Cleanup from our write operation
            return( CONVERTERR_BUFFERFULL );
        }
        
        pmeEvent->dwDeltaTime = tkDelta;
        pmeEvent->dwStreamID = 0;
        pmeEvent->dwEvent = ( pMe->abEvent[0] )
                          | (((DWORD)pMe->abEvent[1] ) << 8 )
                          | (((DWORD)pMe->abEvent[2] ) << 16 )
                          | MEVT_F_SHORT;

        //faB: control the volume with our own volume percentage
        if((( pMe->abEvent[0] & 0xF0) == MIDI_CTRLCHANGE ) &&
            ( pMe->abEvent[1] == MIDICTRL_VOLUME ))
        {
            // If this is a volume change, generate a callback so we can grab
            // the new volume for our cache
            // BP: this seems like this is useless and cause many many many bugs !
            //pmeEvent->dwEvent |= MEVT_F_CALLBACK;
        }
        lpciInfo->dwBytesRecorded += 3 *sizeof(DWORD);
    }
    else if(( pMe->abEvent[0] == MIDI_SYSEX ) ||
            ( pMe->abEvent[0] == MIDI_SYSEXEND ))
    {
        CONS_Printf ( "NOTE: Ignoring SysEx for now.\n");
    }
    else
    {
        DWORD   dwCurrentTempo;
        
        // Better be a meta event.
        //  BYTE        byEvent
        //  BYTE        byEventType
        //  VDWORD      dwEventLength
        //  BYTE        pLongEventData[dwEventLength]
        //
        if (!(pMe->abEvent[0] == MIDI_META))
        {
            I_Error ("AddEventToStreamBuffer: not a META event\n");
        }

        // The only meta-event we care about is change tempo
        //
        if (pMe->abEvent[1] != MIDI_META_TEMPO)
            return( CONVERTERR_METASKIP );
        
        // We should have three bytes of parameter data...
        if (!(pMe->dwEventLength == 3))
        {
            I_Error ("AddEventToStreamBuffer: dwEventLength <> 3\n");
        }

        // Need 3 DWORD's: delta-t, stream-ID, event data
        if( lpciInfo->dwMaxLength - lpciInfo->dwBytesRecorded < 3 *sizeof(DWORD))
        {
            return( CONVERTERR_BUFFERFULL );
        }
        
        pmeEvent->dwDeltaTime = tkDelta;
        pmeEvent->dwStreamID = 0;
        // Note: this is backwards from above because we're converting a single
        //       data value from hi-lo to lo-hi format...
        pmeEvent->dwEvent = ( pMe->pEvent[2] )
            | (((DWORD)pMe->pEvent[1] ) << 8 )
            | (((DWORD)pMe->pEvent[0] ) << 16 );
        
        dwCurrentTempo = pmeEvent->dwEvent;
        pmeEvent->dwEvent |= (((DWORD)MEVT_TEMPO ) << 24 ) | MEVT_F_SHORT;
        
        dwBufferTickLength = ( ifs.dwTimeDivision * 1000 * BUFFER_TIME_LENGTH ) / dwCurrentTempo;
#ifdef DEBUGMIDISTREAM
        CONS_Printf("dwBufferTickLength = %lu", dwBufferTickLength );
#endif
        lpciInfo->dwBytesRecorded += 3 *sizeof(DWORD);
    }

    return( FALSE );
}


// -------------------------
// 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;
    PINTRACKSTATE   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))
        {
            CONS_Printf ( "Read error while reading first delta time of track.\n");
            return TRUE;
        }
    }
    // End of track initialization code

    return FALSE;
}


// -------------------------
// Mid2StreamConvertToBuffer
//
// This function converts MIDI data from the track buffers setup by a previous
// call to Mid2StreamConverterInit().  It will convert data until an error is
// encountered or the output buffer has been filled with as much event data
// as possible, not to exceed dwMaxLength. This function can take a couple
// bit flags, passed through dwFlags. Information about the success/failure
// of this operation and the number of output bytes actually converted will
// be returned in the CONVERTINFO structure pointed at by lpciInfo.
// -------------------------
int Mid2StreamConvertToBuffer( DWORD dwFlags, LPCONVERTINFO lpciInfo )
{
    static INTRACKSTATE *pInTrack, *pInTrackFound;
    static DWORD        dwStatus;
    static DWORD        tkNext;
    static TEMPEVENT    teTemp;

    int     nChkErr;
    DWORD   idx;

    lpciInfo->dwBytesRecorded = 0;

    if( dwFlags & CONVERTF_RESET )
        {
            dwProgressBytes = 0;
            dwStatus = 0;
            ZeroMemory( &teTemp, sizeof(TEMPEVENT));
            pInTrack = pInTrackFound = NULL;
        }

    // If we were already done, then return with a warning...
    if( dwStatus & CONVERTF_STATUS_DONE )
        {
            if( bMidiLooped )
            {
                Mid2StreamRewindConverter();
                dwProgressBytes = 0;
                dwStatus = 0;
            }
            else
                return( CONVERTERR_DONE );
        }
    // The caller is asking us to continue, but we're already hosed because we
    // previously identified something as corrupt, so complain louder this time.
    else if( dwStatus & CONVERTF_STATUS_STUCK )
        {
        return( CONVERTERR_STUCK );
        }
    else if( dwStatus & CONVERTF_STATUS_GOTEVENT )
        {
            // Turn off this bit flag
        dwStatus ^= CONVERTF_STATUS_GOTEVENT;
        
        // Don't add end of track event 'til we're done
        //
        if( teTemp.abEvent[0] == MIDI_META &&
            teTemp.abEvent[1] == MIDI_META_EOT )
        {
        }
        else if(( nChkErr = AddEventToStreamBuffer( &teTemp, lpciInfo ))
                != CONVERTERR_NOERROR )
        {
            if( nChkErr == CONVERTERR_BUFFERFULL )
            {
                // Do some processing and tell caller that this buffer's full
                dwStatus |= CONVERTF_STATUS_GOTEVENT;
                return( CONVERTERR_NOERROR );
            }
            else if( nChkErr == CONVERTERR_METASKIP )
            {
                // We skip by all meta events that aren't tempo changes...
            }
            else
            {
                I_Error ( "Unable to add event to stream buffer." );
            }
        }
    }
    
    for( ; ; )
    {
        pInTrackFound = NULL;
        tkNext = 0xFFFFFFFFL;

        // Find nearest event due
        //
        for (idx = 0, pInTrack = ifs.pTracks; idx < ifs.nTracks; ++idx, ++pInTrack) {
            if ( (!(pInTrack->fdwTrack & ITS_F_ENDOFTRK)) && (pInTrack->tkNextEventDue < tkNext))
            {
                tkNext = pInTrack->tkNextEventDue;
                pInTrackFound = pInTrack;
            }
        }
        
        // None found?  We must be done, so return to the caller with a smile.
        //
        if (!pInTrackFound)
        {
            dwStatus |= CONVERTF_STATUS_DONE;
            // Need to set return buffer members properly
            return( CONVERTERR_NOERROR );
        }
        
        // Ok, get the event header from that track
        //
        if( !GetTrackEvent( pInTrackFound, &teTemp ))
        {
            // Warn future calls that this converter is stuck at a corrupt spot
            // and can't continue
            dwStatus |= CONVERTF_STATUS_STUCK;
            return( CONVERTERR_CORRUPT );
        }
        
        // Don't add end of track event 'til we're done
        //
        if( teTemp.abEvent[0] == MIDI_META &&
            teTemp.abEvent[1] == MIDI_META_EOT )
            continue;
        
        if(( nChkErr = AddEventToStreamBuffer( &teTemp, lpciInfo ))
            != CONVERTERR_NOERROR )
        {
            if( nChkErr == CONVERTERR_BUFFERFULL )
            {
                // Do some processing and tell somebody this buffer is full...
                dwStatus |= CONVERTF_STATUS_GOTEVENT;
                return( CONVERTERR_NOERROR );
            }
            else if( nChkErr == CONVERTERR_METASKIP )
            {
                // We skip by all meta events that aren't tempo changes...
            }
            else
            {
                I_Error( "Unable to add event to stream buffer." );
            }
        }
    }       

    return( CONVERTERR_NOERROR );
    
}

#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -