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)
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)
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)
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)
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)