Exemplo n.º 1
0
void MidiParser::onTimer() {
	uint32 end_time;
	uint32 event_time;

	if (!_position._play_pos || !_driver)
		return;

	_abort_parse = false;
	end_time = _position._play_time + _timer_rate;

	// Scan our hanging notes for any
	// that should be turned off.
	if (_hanging_notes_count) {
		NoteTimer *ptr = &_hanging_notes[0];
		int i;
		for (i = ARRAYSIZE(_hanging_notes); i; --i, ++ptr) {
			if (ptr->time_left) {
				if (ptr->time_left <= _timer_rate) {
					sendToDriver(0x80 | ptr->channel, ptr->note, 0);
					ptr->time_left = 0;
					--_hanging_notes_count;
				} else {
					ptr->time_left -= _timer_rate;
				}
			}
		}
	}

	while (!_abort_parse) {
		EventInfo &info = _next_event;

		event_time = _position._last_event_time + info.delta * _psec_per_tick;
		if (event_time > end_time)
			break;

		// Process the next info.
		_position._last_event_tick += info.delta;
		if (info.event < 0x80) {
			warning("Bad command or running status %02X", info.event);
			_position._play_pos = 0;
			return;
		}

		if (info.event == 0xF0) {
			// SysEx event
			// Check for trailing 0xF7 -- if present, remove it.
			if (info.ext.data[info.length-1] == 0xF7)
				_driver->sysEx(info.ext.data, (uint16)info.length-1);
			else
				_driver->sysEx(info.ext.data, (uint16)info.length);
		} else if (info.event == 0xFF) {
			// META event
			if (info.ext.type == 0x2F) {
				// End of Track must be processed by us,
				// as well as sending it to the output device.
				if (_autoLoop) {
					jumpToTick(0);
					parseNextEvent(_next_event);
				} else {
					stopPlaying();
					_driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length);
				}
				return;
			} else if (info.ext.type == 0x51) {
				if (info.length >= 3) {
					setTempo(info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]);
				}
			}
			_driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length);
		} else {
			if (info.command() == 0x8) {
				activeNote(info.channel(), info.basic.param1, false);
			} else if (info.command() == 0x9) {
				if (info.length > 0)
					hangingNote(info.channel(), info.basic.param1, info.length * _psec_per_tick - (end_time - event_time));
				else
					activeNote(info.channel(), info.basic.param1, true);
			}
			sendToDriver(info.event, info.basic.param1, info.basic.param2);
		}


		if (!_abort_parse) {
			_position._last_event_time = event_time;
			parseNextEvent(_next_event);
		}
	}

	if (!_abort_parse) {
		_position._play_time = end_time;
		_position._play_tick = (_position._play_time - _position._last_event_time) / _psec_per_tick + _position._last_event_tick;
	}
}
Exemplo n.º 2
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())
}