Ejemplo n.º 1
0
DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay)
{
    DWORD len;
    BYTE event, data1 = 0, data2 = 0;
    int i;

    CHECK_FINISHED
    event = track->TrackBegin[track->TrackP++];
    CHECK_FINISHED

    if (event != MIDI_SYSEX && event != MIDI_META && event != MIDI_SYSEXEND)
    {
        // Normal short message
        if ((event & 0xF0) == 0xF0)
        {
            if (MIDI_CommonLengths[event & 15] > 0)
            {
                data1 = track->TrackBegin[track->TrackP++];
                if (MIDI_CommonLengths[event & 15] > 1)
                {
                    data2 = track->TrackBegin[track->TrackP++];
                }
            }
        }
        else if ((event & 0x80) == 0)
        {
            data1 = event;
            event = track->RunningStatus;
        }
        else
        {
            track->RunningStatus = event;
            data1 = track->TrackBegin[track->TrackP++];
        }

        CHECK_FINISHED

        if (MIDI_EventLengths[(event&0x70)>>4] == 2)
        {
            data2 = track->TrackBegin[track->TrackP++];
        }

        switch (event & 0x70)
        {
        case MIDI_PRGMCHANGE & 0x70:
            if (track->EProgramChange)
            {
                event = MIDI_META;
            }
            break;

        case MIDI_CTRLCHANGE & 0x70:
            switch (data1)
            {
            case 7:		// Channel volume
                if (track->EVolume)
                {   // Tracks that use EMIDI volume ignore normal volume changes.
                    event = MIDI_META;
                }
                else
                {
                    data2 = VolumeControllerChange(event & 15, data2);
                }
                break;

            case 7+32:	// Channel volume (LSB)
                if (track->EVolume)
                {
                    event = MIDI_META;
                }
                // It should be safe to pass this straight through to the
                // MIDI device, since it's a very fine amount.
                break;

            case 110:	// EMIDI Track Designation - InitBeat only
                // Instruments 4, 5, 6, and 7 are all FM synth.
                // The rest are all wavetable.
                if (track->PlayedTime < (DWORD)Division)
                {
                    if (data2 == 127)
                    {
                        track->Designation = ~0;
                        track->Designated = true;
                    }
                    else if (data2 <= 9)
                    {
                        track->Designation |= 1 << data2;
                        track->Designated = true;
                    }
                    event = MIDI_META;
                }
                break;

            case 111:	// EMIDI Track Exclusion - InitBeat only
                if (track->PlayedTime < (DWORD)Division)
                {
                    if (track->Designated && data2 <= 9)
                    {
                        track->Designation &= ~(1 << data2);
                    }
                    event = MIDI_META;
                }
                break;

            case 112:	// EMIDI Program Change
                // Ignored unless it also appears in the InitBeat
                if (track->PlayedTime < (DWORD)Division || track->EProgramChange)
                {
                    track->EProgramChange = true;
                    event = 0xC0 | (event & 0x0F);
                    data1 = data2;
                    data2 = 0;
                }
                break;

            case 113:	// EMIDI Volume
                // Ignored unless it also appears in the InitBeat
                if (track->PlayedTime < (DWORD)Division || track->EVolume)
                {
                    track->EVolume = true;
                    data1 = 7;
                    data2 = VolumeControllerChange(event & 15, data2);
                }
                break;

            case 116:	// EMIDI Loop Begin
            {
                // We convert the loop count to XMIDI conventions before clamping.
                // Then we convert it back to EMIDI conventions after clamping.
                // (XMIDI can create "loops" that don't loop. EMIDI cannot.)
                int loopcount = ClampLoopCount(data2 == 0 ? 0 : data2 + 1);
                if (loopcount != 1)
                {
                    track->LoopBegin = track->TrackP;
                    track->LoopDelay = 0;
                    track->LoopCount = loopcount == 0 ? 0 : loopcount - 1;
                    track->LoopFinished = track->Finished;
                }
            }
            event = MIDI_META;
            break;

            case 117:	// EMIDI Loop End
                if (track->LoopCount >= 0 && data2 == 127)
                {
                    if (track->LoopCount == 0 && !m_Looping)
                    {
                        track->Finished = true;
                    }
                    else
                    {
                        if (track->LoopCount > 0 && --track->LoopCount == 0)
                        {
                            track->LoopCount = -1;
                        }
                        track->TrackP = track->LoopBegin;
                        track->Delay = track->LoopDelay;
                        track->Finished = track->LoopFinished;
                    }
                }
                event = MIDI_META;
                break;

            case 118:	// EMIDI Global Loop Begin
            {
                int loopcount = ClampLoopCount(data2 == 0 ? 0 : data2 + 1);
                if (loopcount != 1)
                {
                    for (i = 0; i < NumTracks; ++i)
                    {
                        Tracks[i].LoopBegin = Tracks[i].TrackP;
                        Tracks[i].LoopDelay = Tracks[i].Delay;
                        Tracks[i].LoopCount = loopcount == 0 ? 0 : loopcount - 1;
                        Tracks[i].LoopFinished = Tracks[i].Finished;
                    }
                }
            }
            event = MIDI_META;
            break;

            case 119:	// EMIDI Global Loop End
                if (data2 == 127)
                {
                    for (i = 0; i < NumTracks; ++i)
                    {
                        if (Tracks[i].LoopCount >= 0)
                        {
                            if (Tracks[i].LoopCount == 0 && !m_Looping)
                            {
                                Tracks[i].Finished = true;
                            }
                            else
                            {
                                if (Tracks[i].LoopCount > 0 && --Tracks[i].LoopCount == 0)
                                {
                                    Tracks[i].LoopCount = -1;
                                }
                                Tracks[i].TrackP = Tracks[i].LoopBegin;
                                Tracks[i].Delay = Tracks[i].LoopDelay;
                                Tracks[i].Finished = Tracks[i].LoopFinished;
                            }
                        }
                    }
                }
                event = MIDI_META;
                break;
            }
        }
        events[0] = delay;
        events[1] = 0;
        if (event != MIDI_META && (!track->Designated || (track->Designation & DesignationMask)))
        {
            events[2] = event | (data1<<8) | (data2<<16);
        }
        else
        {
            events[2] = MEVT_NOP << 24;
        }
        events += 3;
    }
    else
    {
        // Skip SysEx events just because I don't want to bother with them.
        // The old MIDI player ignored them too, so this won't break
        // anything that played before.
        if (event == MIDI_SYSEX || event == MIDI_SYSEXEND)
Ejemplo n.º 2
0
DWORD *HMISong::SendCommand (DWORD *events, TrackInfo *track, DWORD delay)
{
	DWORD len;
	BYTE event, data1 = 0, data2 = 0;

	// If the next event comes from the fake track, pop an entry off the note-off queue.
	if (track == FakeTrack)
	{
		AutoNoteOff off;
		NoteOffs.Pop(off);
		events[0] = delay;
		events[1] = 0;
		events[2] = MIDI_NOTEON | off.Channel | (off.Key << 8);
		return events + 3;
	}

	CHECK_FINISHED
	event = track->TrackBegin[track->TrackP++];
	CHECK_FINISHED

	if (event != MIDI_SYSEX && event != MIDI_META && event != MIDI_SYSEXEND && event != 0xFe)
	{
		// Normal short message
		if ((event & 0xF0) == 0xF0)
		{
			if (MIDI_CommonLengths[event & 15] > 0)
			{
				data1 = track->TrackBegin[track->TrackP++];
				if (MIDI_CommonLengths[event & 15] > 1)
				{
					data2 = track->TrackBegin[track->TrackP++];
				}
			}
		}
		else if ((event & 0x80) == 0)
		{
			data1 = event;
			event = track->RunningStatus;
		}
		else
		{
			track->RunningStatus = event;
			data1 = track->TrackBegin[track->TrackP++];
		}

		CHECK_FINISHED

		if (MIDI_EventLengths[(event&0x70)>>4] == 2)
		{
			data2 = track->TrackBegin[track->TrackP++];
		}

		// Monitor channel volume controller changes.
		if ((event & 0x70) == (MIDI_CTRLCHANGE & 0x70) && data1 == 7)
		{
			data2 = VolumeControllerChange(event & 15, data2);
		}

		events[0] = delay;
		events[1] = 0;
		if (event != MIDI_META)
		{
			events[2] = event | (data1<<8) | (data2<<16);
		}
		else
		{
			events[2] = MEVT_NOP << 24;
		}
		events += 3;

		if (ReadVarLen == ReadVarLenHMI && (event & 0x70) == (MIDI_NOTEON & 0x70))
		{ // HMI note on events include the time until an implied note off event.
			NoteOffs.AddNoteOff(track->ReadVarLenHMI(), event & 0x0F, data1);
		}
	}
	else
	{
		// Skip SysEx events just because I don't want to bother with them.
		// The old MIDI player ignored them too, so this won't break
		// anything that played before.
		if (event == MIDI_SYSEX || event == MIDI_SYSEXEND)
Ejemplo n.º 3
0
DWORD *XMISong::SendCommand (DWORD *events, EventSource due, DWORD delay, ptrdiff_t room, bool &sysex_noroom)
{
	DWORD len;
	BYTE event, data1 = 0, data2 = 0;

	if (due == EVENT_Fake)
	{
		AutoNoteOff off;
		NoteOffs.Pop(off);
		events[0] = delay;
		events[1] = 0;
		events[2] = MIDI_NOTEON | off.Channel | (off.Key << 8);
		return events + 3;
	}

	TrackInfo *track = CurrSong;

	sysex_noroom = false;
	size_t start_p = track->EventP;

	CHECK_FINISHED
	event = track->EventChunk[track->EventP++];
	CHECK_FINISHED

	// The actual event type will be filled in below. If it's not a NOP,
	// the events pointer will be advanced once the actual event is written.
	// Otherwise, we do it at the end of the function.
	events[0] = delay;
	events[1] = 0;
	events[2] = MEVT_NOP << 24;

	if (event != MIDI_SYSEX && event != MIDI_META && event != MIDI_SYSEXEND)
	{
		// Normal short message
		if ((event & 0xF0) == 0xF0)
		{
			if (MIDI_CommonLengths[event & 15] > 0)
			{
				data1 = track->EventChunk[track->EventP++];
				if (MIDI_CommonLengths[event & 15] > 1)
				{
					data2 = track->EventChunk[track->EventP++];
				}
			}
		}
		else
		{
			data1 = track->EventChunk[track->EventP++];
		}

		CHECK_FINISHED

		if (MIDI_EventLengths[(event&0x70)>>4] == 2)
		{
			data2 = track->EventChunk[track->EventP++];
		}

		if ((event & 0x70) == (MIDI_CTRLCHANGE & 0x70))
		{
			switch (data1)
			{
			case 7:		// Channel volume
				data2 = VolumeControllerChange(event & 15, data2);
				break;

			case 110:	// XMI channel lock
			case 111:	// XMI channel lock protect
			case 112:	// XMI voice protect
			case 113:	// XMI timbre protect
			case 115:	// XMI indirect controller prefix
			case 118:	// XMI clear beat/bar count
			case 119:	// XMI callback trigger
			case 120:
				event = MIDI_META;		// none of these are relevant to us.
				break;

			case 114:	// XMI patch bank select
				data1 = 0;				// Turn this into a standard MIDI bank select controller.
				break;

			case 116:	// XMI for loop controller
				if (track->ForDepth < MAX_FOR_DEPTH)
				{
					track->ForLoops[track->ForDepth].LoopBegin = track->EventP;
					track->ForLoops[track->ForDepth].LoopCount = ClampLoopCount(data2);
					track->ForLoops[track->ForDepth].LoopFinished = track->Finished;
				}
				track->ForDepth++;
				event = MIDI_META;
				break;

			case 117:	// XMI next loop controller
				if (track->ForDepth > 0)
				{
					int depth = track->ForDepth - 1;
					if (depth < MAX_FOR_DEPTH)
					{
						if (data2 < 64 || (track->ForLoops[depth].LoopCount == 0 && !m_Looping))
						{ // throw away this loop.
							track->ForLoops[depth].LoopCount = 1;
						}
						// A loop count of 0 loops forever.
						if (track->ForLoops[depth].LoopCount == 0 || --track->ForLoops[depth].LoopCount > 0)
						{
							track->EventP = track->ForLoops[depth].LoopBegin;
							track->Finished = track->ForLoops[depth].LoopFinished;
						}
						else
						{ // done with this loop
							track->ForDepth = depth;
						}
					}
					else
					{ // ignore any loops deeper than the max depth
						track->ForDepth = depth;
					}
				}
				event = MIDI_META;
				break;
			}
		}
		events[0] = delay;
		events[1] = 0;
		if (event != MIDI_META)
		{
			events[2] = event | (data1<<8) | (data2<<16);
		}
		events += 3;


		if ((event & 0x70) == (MIDI_NOTEON & 0x70))
		{ // XMI note on events include the time until an implied note off event.
			NoteOffs.AddNoteOff(track->ReadVarLen(), event & 0x0F, data1);
		}
	}
	else
	{
		// SysEx events could potentially not have enough room in the buffer...
		if (event == MIDI_SYSEX || event == MIDI_SYSEXEND)
Ejemplo n.º 4
0
DWORD *XMISong::SendCommand (DWORD *events, EventSource due, DWORD delay)
{
	DWORD len;
	BYTE event, data1 = 0, data2 = 0;

	if (due == EVENT_Fake)
	{
		AutoNoteOff off;
		NoteOffs.Pop(off);
		events[0] = delay;
		events[1] = 0;
		events[2] = MIDI_NOTEON | off.Channel | (off.Key << 8);
		return events + 3;
	}

	TrackInfo *track = CurrSong;

	CHECK_FINISHED
	event = track->EventChunk[track->EventP++];
	CHECK_FINISHED

	if (event != MIDI_SYSEX && event != MIDI_META && event != MIDI_SYSEXEND)
	{
		// Normal short message
		if ((event & 0xF0) == 0xF0)
		{
			if (MIDI_CommonLengths[event & 15] > 0)
			{
				data1 = track->EventChunk[track->EventP++];
				if (MIDI_CommonLengths[event & 15] > 1)
				{
					data2 = track->EventChunk[track->EventP++];
				}
			}
		}
		else
		{
			data1 = track->EventChunk[track->EventP++];
		}

		CHECK_FINISHED

		if (MIDI_EventLengths[(event&0x70)>>4] == 2)
		{
			data2 = track->EventChunk[track->EventP++];
		}

		if ((event & 0x70) == (MIDI_CTRLCHANGE & 0x70))
		{
			switch (data1)
			{
			case 7:		// Channel volume
				data2 = VolumeControllerChange(event & 15, data2);
				break;

			case 110:	// XMI channel lock
			case 111:	// XMI channel lock protect
			case 112:	// XMI voice protect
			case 113:	// XMI timbre protect
			case 115:	// XMI indirect controller prefix
			case 118:	// XMI clear beat/bar count
			case 119:	// XMI callback trigger
			case 120:
				event = MIDI_META;		// none of these are relevant to us.
				break;

			case 114:	// XMI patch bank select
				data1 = 0;				// Turn this into a standard MIDI bank select controller.
				break;

			case 116:	// XMI for loop controller
				if (track->ForDepth < MAX_FOR_DEPTH)
				{
					track->ForLoops[track->ForDepth].LoopBegin = track->EventP;
					track->ForLoops[track->ForDepth].LoopCount = ClampLoopCount(data2);
					track->ForLoops[track->ForDepth].LoopFinished = track->Finished;
				}
				track->ForDepth++;
				event = MIDI_META;
				break;

			case 117:	// XMI next loop controller
				if (track->ForDepth > 0)
				{
					int depth = track->ForDepth - 1;
					if (depth < MAX_FOR_DEPTH)
					{
						if (data2 < 64 || (track->ForLoops[depth].LoopCount == 0 && !m_Looping))
						{ // throw away this loop.
							track->ForLoops[depth].LoopCount = 1;
						}
						// A loop count of 0 loops forever.
						if (track->ForLoops[depth].LoopCount == 0 || --track->ForLoops[depth].LoopCount > 0)
						{
							track->EventP = track->ForLoops[depth].LoopBegin;
							track->Finished = track->ForLoops[depth].LoopFinished;
						}
						else
						{ // done with this loop
							track->ForDepth = depth;
						}
					}
					else
					{ // ignore any loops deeper than the max depth
						track->ForDepth = depth;
					}
				}
				event = MIDI_META;
				break;
			}
		}
		events[0] = delay;
		events[1] = 0;
		if (event != MIDI_META)
		{
			events[2] = event | (data1<<8) | (data2<<16);
		}
		else
		{
			events[2] = MEVT_NOP << 24;
		}
		events += 3;


		if ((event & 0x70) == (MIDI_NOTEON & 0x70))
		{ // XMI note on events include the time until an implied note off event.
			NoteOffs.AddNoteOff(track->ReadVarLen(), event & 0x0F, data1);
		}
	}
	else
	{
		// Skip SysEx events just because I don't want to bother with them.
		// The old MIDI player ignored them too, so this won't break
		// anything that played before.
		if (event == MIDI_SYSEX || event == MIDI_SYSEXEND)
Ejemplo n.º 5
0
uint32_t *HMISong::SendCommand (uint32_t *events, TrackInfo *track, uint32_t delay, ptrdiff_t room, bool &sysex_noroom)
{
	uint32_t len;
	uint8_t event, data1 = 0, data2 = 0;

	// If the next event comes from the fake track, pop an entry off the note-off queue.
	if (track == FakeTrack)
	{
		AutoNoteOff off;
		NoteOffs.Pop(off);
		events[0] = delay;
		events[1] = 0;
		events[2] = MIDI_NOTEON | off.Channel | (off.Key << 8);
		return events + 3;
	}

	sysex_noroom = false;
	size_t start_p = track->TrackP;

	CHECK_FINISHED
	event = track->TrackBegin[track->TrackP++];
	CHECK_FINISHED

	// The actual event type will be filled in below. If it's not a NOP,
	// the events pointer will be advanced once the actual event is written.
	// Otherwise, we do it at the end of the function.
	events[0] = delay;
	events[1] = 0;
	events[2] = MEVENT_NOP << 24;

	if (event != MIDI_SYSEX && event != MIDI_META && event != MIDI_SYSEXEND && event != 0xFe)
	{
		// Normal short message
		if ((event & 0xF0) == 0xF0)
		{
			if (MIDI_CommonLengths[event & 15] > 0)
			{
				data1 = track->TrackBegin[track->TrackP++];
				if (MIDI_CommonLengths[event & 15] > 1)
				{
					data2 = track->TrackBegin[track->TrackP++];
				}
			}
		}
		else if ((event & 0x80) == 0)
		{
			data1 = event;
			event = track->RunningStatus;
		}
		else
		{
			track->RunningStatus = event;
			data1 = track->TrackBegin[track->TrackP++];
		}

		CHECK_FINISHED

		if (MIDI_EventLengths[(event&0x70)>>4] == 2)
		{
			data2 = track->TrackBegin[track->TrackP++];
		}

		// Monitor channel volume controller changes.
		if ((event & 0x70) == (MIDI_CTRLCHANGE & 0x70) && data1 == 7)
		{
			data2 = VolumeControllerChange(event & 15, data2);
		}

		if (event != MIDI_META)
		{
			events[2] = event | (data1<<8) | (data2<<16);
		}

		if (ReadVarLen == ReadVarLenHMI && (event & 0x70) == (MIDI_NOTEON & 0x70))
		{ // HMI note on events include the time until an implied note off event.
			NoteOffs.AddNoteOff(track->ReadVarLenHMI(), event & 0x0F, data1);
		}
	}
	else
	{
		// SysEx events could potentially not have enough room in the buffer...
		if (event == MIDI_SYSEX || event == MIDI_SYSEXEND)