Example #1
0
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);
		}
	}
}
Example #2
0
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;
	}
}
Example #3
0
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())
}
Example #4
0
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;
	}
}
Example #5
0
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;
		}
	}
}