void MidiParser_SMF::parseNextEvent(EventInfo &info) { info.start = _position._play_pos; info.delta = readVLQ(_position._play_pos); // Process the next info. If mpMalformedPitchBends // was set, we must skip over any pitch bend events // because they are from Simon games and are not // real pitch bend events, they're just two-byte // prefixes before the real info. do { if ((_position._play_pos[0] & 0xF0) >= 0x80) info.event = *(_position._play_pos++); else info.event = _position._running_status; } while (_malformedPitchBends && (info.event & 0xF0) == 0xE0 && _position._play_pos++); if (info.event < 0x80) return; _position._running_status = info.event; switch (info.command()) { case 0x9: // Note On info.basic.param1 = *(_position._play_pos++); info.basic.param2 = *(_position._play_pos++); if (info.basic.param2 == 0) info.event = info.channel() | 0x80; info.length = 0; break; case 0xC: case 0xD: info.basic.param1 = *(_position._play_pos++); info.basic.param2 = 0; break; case 0x8: case 0xA: case 0xB: case 0xE: info.basic.param1 = *(_position._play_pos++); info.basic.param2 = *(_position._play_pos++); info.length = 0; break; case 0xF: // System Common, Meta or SysEx event switch (info.event & 0x0F) { case 0x2: // Song Position Pointer info.basic.param1 = *(_position._play_pos++); info.basic.param2 = *(_position._play_pos++); break; case 0x3: // Song Select info.basic.param1 = *(_position._play_pos++); info.basic.param2 = 0; break; case 0x6: case 0x8: case 0xA: case 0xB: case 0xC: case 0xE: info.basic.param1 = info.basic.param2 = 0; break; case 0x0: // SysEx info.length = readVLQ(_position._play_pos); info.ext.data = _position._play_pos; _position._play_pos += info.length; break; case 0xF: // META event info.ext.type = *(_position._play_pos++); info.length = readVLQ(_position._play_pos); info.ext.data = _position._play_pos; _position._play_pos += info.length; break; default: warning("MidiParser_SMF::parseNextEvent: Unsupported event code %x", info.event); } } }
void MidiParser_S1D::parseNextEvent(EventInfo &info) { info.start = _position._play_pos; info.delta = _no_delta ? 0 : readVLQ2(_position._play_pos); _no_delta = false; info.event = *(_position._play_pos++); if (info.command() < 0x8) { _no_delta = true; info.event += 0x80; } switch (info.command()) { case 0x8: info.basic.param1 = *(_position._play_pos++); info.basic.param2 = 0; info.length = 0; break; case 0x9: info.basic.param1 = *(_position._play_pos++); info.basic.param2 = *(_position._play_pos++); // I'm ASSUMING this byte is velocity! info.length = 0; break; case 0xA: case 0xB: // I'm not sure what these are meant to do, or what the // parameter is. Elvira 1 needs them, though, and who am I to // argue with her? info.basic.param1 = *(_position._play_pos++); info.basic.param2 = 0; break; case 0xC: info.basic.param1 = *(_position._play_pos++); info.basic.param2 = 0; ++_position._play_pos; // I have NO IDEA what the second byte is for. break; case 0xD: // Triggered by MOD0/MOD1/MOD2/MOD3/MOD4/MOD6/MOD7/MOD8/MOD9 in Elvira 2 // Triggered by MOD0/MOD2/MOD3/MOD5/MOD6/MOD7/MOD8/MOD9/MOD10/MOD12/MOD14/MOD15/MOD20 in Waxworks break; case 0xE: // Triggered by MOD9 in Elvira 1 // Triggered by MOD3/MOD5 in Elvira 2 // Triggered by MOD3/MOD7/MOD8/MOD13 in Waxworks break; case 0xF: switch (info.event & 0x0F) { case 0x0: // Trigged by MOD2/MOD6/MOD15 in Waxworks // Pure guesswork info.ext.type = *(_position._play_pos++); info.length = readVLQ(_position._play_pos); info.ext.data = _position._play_pos; break; case 0x3: // Not sure, Song Select? // Trigged by MOD1/MOD7/MOD10 in Elvira 1 info.basic.param1 = *(_position._play_pos++); info.basic.param2 = 0; break; case 0x4: // Trigged by MOD8 in Elvira 1 break; case 0x7: // Trigged by MOD6 in Elvira 2 // Trigged by MOD5 in Waxworks break; case 0x8: // Not sure, ? // Trigged by MOD19 in Waxworks info.basic.param1 = info.basic.param2 = 0; break; case 0xA: // Trigged by MOD5 in Elvira 2 break; case 0xC: // This means End of Track. // Rewrite in SMF (MIDI transmission) form. info.event = 0xFF; info.ext.type = 0x2F; info.length = 0; break; case 0xF: // Not sure, META event? // Trigged by MOD8/MOD9/MOD11/MOD12/MOD13 in Waxworks info.ext.type = *(_position._play_pos++); info.length = readVLQ(_position._play_pos); info.ext.data = _position._play_pos; _position._play_pos += info.length; break; default: error("MidiParser_S1D: Unexpected type 0x%02X found", (int) info.event); break; } break; default: error("MidiParser_S1D: Unexpected event 0x%02X found", (int) info.command()); break; } }
void MidiParser_SH::parseNextEvent(EventInfo &info) { Common::StackLock lock(_mutex); // warning("parseNextEvent"); // there is no delta right at the start of the music data // this order is essential, otherwise notes will get delayed or even go missing if (_position._playPos != _tracks[0]) { info.delta = *(_position._playPos++); } else { info.delta = 0; } info.start = _position._playPos; info.event = *_position._playPos++; //warning("Event %x", info.event); _position._runningStatus = info.event; switch (info.command()) { case 0xC: { // program change int idx = *_position._playPos++; info.basic.param1 = idx & 0x7f; info.basic.param2 = 0; } break; case 0xD: info.basic.param1 = *_position._playPos++; info.basic.param2 = 0; break; case 0xB: info.basic.param1 = *_position._playPos++; info.basic.param2 = *_position._playPos++; info.length = 0; break; case 0x8: case 0x9: case 0xA: case 0xE: info.basic.param1 = *(_position._playPos++); info.basic.param2 = *(_position._playPos++); if (info.command() == 0x9 && info.basic.param2 == 0) { // NoteOn with param2==0 is a NoteOff info.event = info.channel() | 0x80; } info.length = 0; break; case 0xF: if (info.event == 0xFF) { error("SysEx META event 0xFF"); byte type = *(_position._playPos++); switch(type) { case 0x2F: // End of Track allNotesOff(); stopPlaying(); unloadMusic(); return; case 0x51: warning("TODO: 0xFF / 0x51"); return; default: warning("TODO: 0xFF / %x Unknown", type); break; } } else if (info.event == 0xFC) { // Official End-Of-Track signal debugC(kDebugLevelMusic, "Music: System META event 0xFC"); byte type = *(_position._playPos++); switch (type) { case 0x80: // end of track, triggers looping debugC(kDebugLevelMusic, "Music: META event triggered looping"); jumpToTick(0, true, true, false); break; case 0x81: // end of track, stop playing debugC(kDebugLevelMusic, "Music: META event triggered music stop"); stopPlaying(); unloadMusic(); break; default: error("MidiParser_SH::parseNextEvent: Unknown META event 0xFC type %x", type); break; } } else { warning("TODO: %x / Unknown", info.event); break; } break; default: warning("MidiParser_SH::parseNextEvent: Unsupported event code %x", info.event); break; }// switch (info.command()) }
void MidiParser_RO::parseNextEvent (EventInfo &info) { _markerCount += _lastMarkerCount; _lastMarkerCount = 0; info.delta = 0; do { info.start = _position._play_pos; info.event = *(_position._play_pos++); if (info.command() == 0xA) { ++_lastMarkerCount; info.event = 0xF0; } else if (info.event == 0xF0 || info.event == 0xF1) { byte delay = *(_position._play_pos++); info.delta += delay; if (info.event == 0xF1) { // This event is, as far as we have been able // to determine, only used in one single song // in EGA Loom. It seems to be meant for adding // values greater than 255 to info.delta. See // bug #1498785. info.delta += 256; } continue; } break; } while (true); // Seems to indicate EOT if (info.event == 0) { info.event = 0xFF; info.ext.type = 0x2F; info.length = 0; info.ext.data = 0; return; } if (info.event < 0x80) return; _position._running_status = info.event; switch (info.command()) { case 0xC: info.basic.param1 = *(_position._play_pos++); info.basic.param2 = 0; break; case 0x8: case 0x9: case 0xB: info.basic.param1 = *(_position._play_pos++); info.basic.param2 = *(_position._play_pos++); if (info.command() == 0x9 && info.basic.param2 == 0) info.event = info.channel() | 0x80; info.length = 0; break; case 0xF: // Marker and EOT messages info.length = 0; info.ext.data = 0; if (info.event == 0xFF) { _autoLoop = true; info.ext.type = 0x2F; } else { info.ext.type = 0x7F; // Bogus META } info.event = 0xFF; break; } }
void MidiParser_S1D::parseNextEvent(EventInfo &info) { info.start = _position._playPos; info.length = 0; info.delta = _noDelta ? 0 : readVLQ2(_position._playPos); _noDelta = false; info.event = *_position._playPos++; if (!(info.event & 0x80)) { _noDelta = true; info.event |= 0x80; } if (info.event == 0xFC) { // This means End of Track. // Rewrite in SMF (MIDI transmission) form. info.event = 0xFF; info.ext.type = 0x2F; } else { switch (info.command()) { case 0x8: // note off info.basic.param1 = *_position._playPos++; info.basic.param2 = 0; break; case 0x9: // note on info.basic.param1 = *_position._playPos++; info.basic.param2 = *_position._playPos++; // Rewrite note on events with velocity 0 as note off events. // This is the actual meaning of this, but theoretically this // should not need to be rewritten, since all MIDI devices should // interpret it like that. On the other hand all our MidiParser // implementations do it and there seems to be code in MidiParser // which relies on this for tracking active notes. if (info.basic.param2 == 0) { info.event = info.channel() | 0x80; } break; case 0xA: { // loop control // In case the stop mode(?) is set to 0x80 this will stop the // track over here. const int16 loopIterations = int8(*_position._playPos++); if (!loopIterations) { _loops[info.channel()].start = _position._playPos; } else { if (!_loops[info.channel()].timer) { if (_loops[info.channel()].start) { _loops[info.channel()].timer = uint16(loopIterations); _loops[info.channel()].end = _position._playPos; // Go to the start of the loop _position._playPos = _loops[info.channel()].start; } } else { if (_loops[info.channel()].timer) _position._playPos = _loops[info.channel()].start; --_loops[info.channel()].timer; } } // We need to read the next midi event here. Since we can not // safely pass this event to the MIDI event processing. chainEvent(info); } break; case 0xB: // auto stop marker(?) // In case the stop mode(?) is set to 0x80 this will stop the // track. // We need to read the next midi event here. Since we can not // safely pass this event to the MIDI event processing. chainEvent(info); break; case 0xC: // program change info.basic.param1 = *_position._playPos++; info.basic.param2 = 0; break; case 0xD: // jump to loop end if (_loops[info.channel()].end) _position._playPos = _loops[info.channel()].end; // We need to read the next midi event here. Since we can not // safely pass this event to the MIDI event processing. chainEvent(info); break; default: // The original called some other function from here, which seems // not to be MIDI related. warning("MidiParser_S1D: default case %d", info.channel()); // We need to read the next midi event here. Since we can not // safely pass this event to the MIDI event processing. chainEvent(info); break; } } }