示例#1
0
void CALLBACK Win32MidiIn::midiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
	Q_UNUSED(dwParam2);

	MidiSession *midiSession = (MidiSession *)dwInstance;

	LPMIDIHDR pMIDIhdr = (LPMIDIHDR)dwParam1;
	if (wMsg == MIM_LONGDATA) {
		if (pMIDIhdr->dwBytesRecorded == 0) {
			// 0 length means returning the buffer to the application when closing
			return;
		}
		// Use QMidiStreamParser to extract well-formed SysEx messages from buffer
		QMidiStreamParser &qMidiStreamParser = *midiSession->getQMidiStreamParser();
		qMidiStreamParser.setTimestamp(MasterClock::getClockNanos());
		qMidiStreamParser.parseStream((BYTE *)pMIDIhdr->lpData, pMIDIhdr->dwBytesRecorded);

		// Add SysEx Buffer for reuse
		if (midiInAddBuffer(hMidiIn, pMIDIhdr, sizeof(MIDIHDR)) != MMSYSERR_NOERROR) {
			QMessageBox::critical(NULL, "Win32MidiIn Error", "Failed to add SysEx Buffer for reuse");
			return;
		}
		return;
	}
	if (wMsg == MIM_DATA) {
		// No need to use QMidiStreamParser for short messages: they are guaranteed to have explicit status byte
		// if ((dwParam1 & 0xF8) == 0xF8) // No support for System Realtime yet
		midiSession->getSynthRoute()->pushMIDIShortMessage(dwParam1, MasterClock::getClockNanos());
	}
}
示例#2
0
LRESULT CALLBACK Win32MidiDriver::midiInProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	switch (uMsg) {
	case WM_APP: {
		// Closing session
		MidiSession *midiSession = (MidiSession *)wParam;
		if (driver->midiSessions.indexOf(midiSession) < 0) {
			qDebug() << "Win32MidiDriver: Invalid midiSession handle supplied";
			return 0;
		}
		qDebug() << "Win32MidiDriver: Session" << midiSession << "finished";
		driver->deleteMidiSession(midiSession);
		return 1;
	}

	case WM_COPYDATA: {
		COPYDATASTRUCT *cds = (COPYDATASTRUCT *)lParam;
		MidiSession *midiSession = (MidiSession *)cds->dwData;
		DWORD *data = (DWORD *)cds->lpData;
		if (data[0] == 0) { // Special value, mark of a non-Sysex message
			if (data[1] == (DWORD)-1) { // Special value, mark of a handshaking message
				// Sync the timesource in the driver with MasterClock
				LARGE_INTEGER t = {{data[3], (LONG)data[4]}};
				startMasterClock = t.QuadPart - MasterClock::getClockNanos();
				// Process handshaking message
				QString appName = QFileInfo(QString((const char *)&data[5])).fileName();
				midiSession = driver->createMidiSession(appName);
				driver->showBalloon("Connected application:", appName);
				qDebug() << "Win32MidiDriver: Connected application" << appName;
				qDebug() << "Win32MidiDriver: Session" << midiSession << "protocol version" << data[2];
				if (!midiSession) {
					qDebug() << "Win32MidiDriver: Failed to create new session";
					return 0;
				}
				return (LRESULT)midiSession;
			} else if (data[1] == 0) { // Special value, mark of a short MIDI message
				// Process short MIDI message
				if (driver->midiSessions.indexOf(midiSession) < 0) {
					qDebug() << "Win32MidiDriver: Invalid midiSession handle supplied";
					return 0;
				}
				LARGE_INTEGER t = {{data[2], (LONG)data[3]}};
//				qDebug() << "D" << 1e-6 * ((t.QuadPart - startMasterClock) - MasterClock::getClockNanos());
				midiSession->getSynthRoute()->pushMIDIShortMessage(data[4], t.QuadPart - startMasterClock);
				return 1;
			}
		} else {
			// Process Sysex
			if (driver->midiSessions.indexOf(midiSession) < 0) {
				qDebug() << "Win32MidiDriver: Invalid midiSession handle supplied";
				return 0;
			}
			midiSession->getSynthRoute()->pushMIDISysex((MT32Emu::Bit8u *)cds->lpData, cds->cbData, MasterClock::getClockNanos());
			return 1;
		}
	}

	default:
		return DefWindowProc(hwnd, uMsg, wParam, lParam);
	}
}
示例#3
0
void SMFProcessor::run() {
	MidiSession *session = driver->createMidiSession(QFileInfo(fileName).fileName());
	SynthRoute *synthRoute = session->getSynthRoute();
	const MidiEventList &midiEvents = parser.getMIDIEvents();
	midiTick = parser.getMidiTick();
	quint32 totalSeconds = estimateRemainingTime(midiEvents, 0);
	MasterClockNanos startNanos = MasterClock::getClockNanos();
	MasterClockNanos currentNanos = startNanos;
	for (int i = 0; i < midiEvents.count(); i++) {
		const MidiEvent &e = midiEvents.at(i);
		currentNanos += e.getTimestamp() * midiTick;
		while (!stopProcessing && synthRoute->getState() == SynthRouteState_OPEN) {
			if (bpmUpdated) {
				bpmUpdated = false;
				totalSeconds = (currentNanos - startNanos) / MasterClock::NANOS_PER_SECOND + estimateRemainingTime(midiEvents, i + 1);
			}
			if (driver->seekPosition > -1) {
				SMFProcessor::sendAllNotesOff(synthRoute);
				MasterClockNanos seekNanos = totalSeconds * driver->seekPosition * MasterClock::NANOS_PER_MILLISECOND;
				MasterClockNanos eventNanos = currentNanos - e.getTimestamp() * midiTick - startNanos;
				if (seekNanos < eventNanos) {
					i = 0;
					eventNanos = 0;
					midiTick = parser.getMidiTick();
					emit driver->tempoUpdated(0);
				}
				i = seek(synthRoute, midiEvents, i, seekNanos, eventNanos) - 1;
				currentNanos = MasterClock::getClockNanos();
				startNanos = currentNanos - seekNanos;
				break;
			}
			emit driver->playbackTimeChanged(MasterClock::getClockNanos() - startNanos, totalSeconds);
			MasterClockNanos delay = currentNanos - MasterClock::getClockNanos();
			if (driver->fastForwardingFactor > 1) {
				MasterClockNanos timeShift = delay - (delay / driver->fastForwardingFactor);
				delay -= timeShift;
				currentNanos -= timeShift;
				startNanos -= timeShift;
			}
			if (delay < MasterClock::NANOS_PER_MILLISECOND) break;
			usleep(((delay < MAX_SLEEP_TIME ? delay : MAX_SLEEP_TIME) - MasterClock::NANOS_PER_MILLISECOND) / MasterClock::NANOS_PER_MICROSECOND);
		}
		if (stopProcessing || synthRoute->getState() != SynthRouteState_OPEN) break;
		if (driver->seekPosition > -1) {
			driver->seekPosition = -1;
			continue;
		}
		switch (e.getType()) {
			case SHORT_MESSAGE:
				synthRoute->pushMIDIShortMessage(e.getShortMessage(), currentNanos);
				break;
			case SYSEX:
				synthRoute->pushMIDISysex(e.getSysexData(), e.getSysexLen(), currentNanos);
				break;
			case SET_TEMPO: {
				uint tempo = e.getShortMessage();
				midiTick = parser.getMidiTick(tempo);
				emit driver->tempoUpdated(MidiParser::MICROSECONDS_PER_MINUTE / tempo);
				break;
			}
			default:
				break;
		}
	}
	SMFProcessor::sendAllNotesOff(synthRoute);
	emit driver->playbackTimeChanged(0, 0);
	qDebug() << "SMFDriver: processor thread stopped";
	driver->deleteMidiSession(session);
	if (!stopProcessing) emit driver->playbackFinished();
}