Example #1
0
void MidiParser_XMIDI::parseNextEvent(EventInfo &info) {
	info.start = _position._play_pos;
	info.delta = readVLQ2(_position._play_pos) - _inserted_delta;

	// Process the next event.
	_inserted_delta = 0;
	info.event = *(_position._play_pos++);
	switch (info.event >> 4) {
	case 0x9: // Note On
		info.basic.param1 = *(_position._play_pos++);
		info.basic.param2 = *(_position._play_pos++);
		info.length = readVLQ(_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 0xE:
		info.basic.param1 = *(_position._play_pos++);
		info.basic.param2 = *(_position._play_pos++);
		break;

	case 0xB:
		info.basic.param1 = *(_position._play_pos++);
		info.basic.param2 = *(_position._play_pos++);

		// This isn't a full XMIDI implementation, but it should
		// hopefully be "good enough" for most things.

		switch (info.basic.param1) {
		// Simplified XMIDI looping.
		case 0x74: {	// XMIDI_CONTROLLER_FOR_LOOP
				byte *pos = _position._play_pos;
				if (_loopCount < ARRAYSIZE(_loop) - 1)
					_loopCount++;
				else
					warning("XMIDI: Exceeding maximum loop count %d", ARRAYSIZE(_loop));

				_loop[_loopCount].pos = pos;
				_loop[_loopCount].repeat = info.basic.param2;
				break;
			}

		case 0x75:	// XMIDI_CONTORLLER_NEXT_BREAK
			if (_loopCount >= 0) {
				if (info.basic.param2 < 64) {
					// End the current loop.
					_loopCount--;
				} else {
					// Repeat 0 means "loop forever".
					if (_loop[_loopCount].repeat) {
						if (--_loop[_loopCount].repeat == 0)
							_loopCount--;
						else
							_position._play_pos = _loop[_loopCount].pos;
					} else {
						_position._play_pos = _loop[_loopCount].pos;
					}
				}
			}
			break;

		case 0x77:	// XMIDI_CONTROLLER_CALLBACK_TRIG
			if (_callbackProc)
				_callbackProc(info.basic.param2, _callbackData);
			break;

		case 0x6e:	// XMIDI_CONTROLLER_CHAN_LOCK
		case 0x6f:	// XMIDI_CONTROLLER_CHAN_LOCK_PROT
		case 0x70:	// XMIDI_CONTROLLER_VOICE_PROT
		case 0x71:	// XMIDI_CONTROLLER_TIMBRE_PROT
		case 0x72:	// XMIDI_CONTROLLER_BANK_CHANGE
		case 0x73:	// XMIDI_CONTROLLER_IND_CTRL_PREFIX
		case 0x76:	// XMIDI_CONTROLLER_CLEAR_BB_COUNT
		case 0x78:	// XMIDI_CONTROLLER_SEQ_BRANCH_INDEX
		default:
			if (info.basic.param1 >= 0x6e && info.basic.param1 <= 0x78) {
				warning("Unsupported XMIDI controller %d (0x%2x)",
					info.basic.param1, info.basic.param1);
			}
		}

		// Should we really keep passing the XMIDI controller events to
		// the MIDI driver, or should we turn them into some kind of
		// NOP events? (Dummy meta events, perhaps?) Ah well, it has
		// worked so far, so it shouldn't cause any damage...

		break;

	case 0xF: // 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;
			if (info.ext.type == 0x51 && info.length == 3) {
				// Tempo event. We want to make these constant 500,000.
				info.ext.data[0] = 0x07;
				info.ext.data[1] = 0xA1;
				info.ext.data[2] = 0x20;
			}
			break;

		default:
			warning("MidiParser_XMIDI::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_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;
		}
	}
}