Index: build/premake/ext-rtmidi.lua
===================================================================
--- build/premake/ext-rtmidi.lua	(nonexistent)
+++ build/premake/ext-rtmidi.lua	(working copy)
@@ -0,0 +1,26 @@
+ 
+ project "rtmidi"
+  uuid "05BBD03D-0985-4D76-8DDD-534DA631C3A8"
+  language "C++"
+  location ( "../../build/" .. mpt_projectpathname .. "/ext" )
+  mpt_projectname = "rtmidi"
+  dofile "../../build/premake/premake-defaults-LIBorDLL.lua"
+  dofile "../../build/premake/premake-defaults.lua"
+  dofile "../../build/premake/premake-defaults-winver.lua"
+  targetname "openmpt-rtmidi"
+	filter {}
+	filter { "action:vs*" }
+		characterset "Unicode"
+	filter {}
+  files {
+   "../../include/rtmidi/RtMidi.cpp"
+  }
+  files {
+   "../../include/rtmidi/RtMidi.h"
+  }
+  defines {
+   "__WINDOWS_MM__"
+  }
+  links {
+   "winmm"
+  }

Property changes on: build/premake/ext-rtmidi.lua
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/x-lua
\ No newline at end of property
Index: build/premake/mpt-OpenMPT-VSTi.lua
===================================================================
--- build/premake/mpt-OpenMPT-VSTi.lua	(revision 7555)
+++ build/premake/mpt-OpenMPT-VSTi.lua	(working copy)
@@ -87,8 +87,8 @@
    "opus",
    "opusfile",
    "portaudio",
-   "portmidi",
    "r8brain",
+   "rtmidi",
    "soundtouch",
    "vorbis",
   }
Index: build/premake/mpt-OpenMPT.lua
===================================================================
--- build/premake/mpt-OpenMPT.lua	(revision 7555)
+++ build/premake/mpt-OpenMPT.lua	(working copy)
@@ -122,8 +122,8 @@
    "opus",
    "opusfile",
    "portaudio",
-   "portmidi",
    "r8brain",
+   "rtmidi",
    "soundtouch",
    "vorbis",
   }
Index: build/premake/premake.lua
===================================================================
--- build/premake/premake.lua	(revision 7555)
+++ build/premake/premake.lua	(working copy)
@@ -376,8 +376,8 @@
  dofile "../../build/premake/ext-opus.lua"
  dofile "../../build/premake/ext-opusfile.lua"
  dofile "../../build/premake/ext-portaudio.lua"
- dofile "../../build/premake/ext-portmidi.lua"
  dofile "../../build/premake/ext-r8brain.lua"
+ dofile "../../build/premake/ext-rtmidi.lua"
  dofile "../../build/premake/ext-smbPitchShift.lua"
  dofile "../../build/premake/ext-soundtouch.lua"
  dofile "../../build/premake/ext-UnRAR.lua"
@@ -405,8 +405,8 @@
  dofile "../../build/premake/ext-opus.lua"
  dofile "../../build/premake/ext-opusfile.lua"
  dofile "../../build/premake/ext-portaudio.lua"
- dofile "../../build/premake/ext-portmidi.lua"
  dofile "../../build/premake/ext-r8brain.lua"
+ dofile "../../build/premake/ext-rtmidi.lua"
  dofile "../../build/premake/ext-smbPitchShift.lua"
  dofile "../../build/premake/ext-soundtouch.lua"
  dofile "../../build/premake/ext-UnRAR.lua"
@@ -429,8 +429,8 @@
  dofile "../../build/premake/ext-opus.lua"
  dofile "../../build/premake/ext-opusfile.lua"
  dofile "../../build/premake/ext-portaudio.lua"
- dofile "../../build/premake/ext-portmidi.lua"
  dofile "../../build/premake/ext-r8brain.lua"
+ dofile "../../build/premake/ext-rtmidi.lua"
  dofile "../../build/premake/ext-smbPitchShift.lua"
  dofile "../../build/premake/ext-soundtouch.lua"
  dofile "../../build/premake/ext-UnRAR.lua"
@@ -455,8 +455,8 @@
  dofile "../../build/premake/ext-opus.lua"
  dofile "../../build/premake/ext-opusfile.lua"
  dofile "../../build/premake/ext-portaudio.lua"
- dofile "../../build/premake/ext-portmidi.lua"
  dofile "../../build/premake/ext-r8brain.lua"
+ dofile "../../build/premake/ext-rtmidi.lua"
  dofile "../../build/premake/ext-smbPitchShift.lua"
  dofile "../../build/premake/ext-soundtouch.lua"
  dofile "../../build/premake/ext-UnRAR.lua"
@@ -481,8 +481,8 @@
  dofile "../../build/premake/ext-opus.lua"
  dofile "../../build/premake/ext-opusfile.lua"
  dofile "../../build/premake/ext-portaudio.lua"
- dofile "../../build/premake/ext-portmidi.lua"
  dofile "../../build/premake/ext-pugixml.lua"
+ dofile "../../build/premake/ext-rtmidi.lua"
  dofile "../../build/premake/ext-r8brain.lua"
  dofile "../../build/premake/ext-smbPitchShift.lua"
  dofile "../../build/premake/ext-soundtouch.lua"
Index: plugins/MidiInOut/MidiInOut.cpp
===================================================================
--- plugins/MidiInOut/MidiInOut.cpp	(revision 7555)
+++ plugins/MidiInOut/MidiInOut.cpp	(working copy)
@@ -20,12 +20,16 @@
 OPENMPT_NAMESPACE_BEGIN
 
 
-int MidiInOut::numInstances = 0;
-
 IMixPlugin* MidiInOut::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
 //------------------------------------------------------------------------------------------------
 {
-	return new (std::nothrow) MidiInOut(factory, sndFile, mixStruct);
+	try
+	{
+		return new (std::nothrow) MidiInOut(factory, sndFile, mixStruct);
+	} catch(RtMidiError &)
+	{
+		return nullptr;
+	}
 }
 
 
@@ -33,14 +37,10 @@
 	: IMidiPlugin(factory, sndFile, mixStruct)
 	, latencyCompensation(true)
 	, programName(_T("Default"))
+	, inputDevice(midiIn)
+	, outputDevice(midiOut)
 //---------------------------------------------------------------------------------------
 {
-	if(!numInstances++)
-	{
-		Pt_Start(1, nullptr, nullptr);
-		Pm_Initialize();
-	}
-
 	m_mixBuffer.Initialize(2, 2);
 	InsertIntoFactoryList();
 }
@@ -50,13 +50,6 @@
 //---------------------
 {
 	Suspend();
-
-	if(--numInstances == 0)
-	{
-		// This terminates MIDI output for all instances of the plugin, so only ever do it if this was the only instance left.
-		Pm_Terminate();
-		Pt_Stop();
-	}
 }
 
 
@@ -127,9 +120,9 @@
 		return;
 
 	uint32 nameStrSize = file.ReadUint32LE();
-	PmDeviceID inID = file.ReadUint32LE();
+	MidiDevice::ID inID = file.ReadUint32LE();
 	uint32 inStrSize = file.ReadUint32LE();
-	PmDeviceID outID = file.ReadUint32LE();
+	MidiDevice::ID outID = file.ReadUint32LE();
 	uint32 outStrSize = file.ReadUint32LE();
 	latencyCompensation = file.ReadUint32LE() != 0;
 
@@ -139,16 +132,21 @@
 
 	file.ReadString<mpt::String::maybeNullTerminated>(s, inStrSize);
 	s = mpt::ToCharset(mpt::CharsetLocale, mpt::CharsetUTF8, s);
-	if(s != GetDeviceName(inID) || !IsInputDevice(inID))
+	if(s != inputDevice.GetPortName(inID))
 	{
 		// Stored name differs from actual device name - try finding another device with the same name.
-		const PmDeviceInfo *device;
-		for(PmDeviceID i = 0; (device = Pm_GetDeviceInfo(i)) != nullptr; i++)
+		unsigned int ports = midiIn.getPortCount();
+		for(unsigned int i = 0; i < ports; i++)
 		{
-			if(device->input && s == device->name)
+			try
 			{
-				inID = i;
-				break;
+				if(s == inputDevice.GetPortName(i))
+				{
+					inID = i;
+					break;
+				}
+			} catch(RtMidiError &)
+			{
 			}
 		}
 	}
@@ -155,16 +153,21 @@
 
 	file.ReadString<mpt::String::maybeNullTerminated>(s, outStrSize);
 	s = mpt::ToCharset(mpt::CharsetLocale, mpt::CharsetUTF8, s);
-	if(s != GetDeviceName(outID) || !IsOutputDevice(outID))
+	if(s != outputDevice.GetPortName(outID))
 	{
 		// Stored name differs from actual device name - try finding another device with the same name.
-		const PmDeviceInfo *device;
-		for(PmDeviceID i = 0; (device = Pm_GetDeviceInfo(i)) != nullptr; i++)
+		unsigned int ports = midiOut.getPortCount();
+		for(unsigned int i = 0; i < ports; i++)
 		{
-			if(device->output && s == device->name)
+			try
 			{
-				outID = i;
-				break;
+				if(s == outputDevice.GetPortName(i))
+				{
+					outID = i;
+					break;
+				}
+			} catch(RtMidiError &)
+			{
 			}
 		}
 	}
@@ -177,7 +180,7 @@
 void MidiInOut::SetParameter(PlugParamIndex index, PlugParamValue value)
 //----------------------------------------------------------------------
 {
-	PmDeviceID newDevice = ParameterToDeviceID(value);
+	MidiDevice::ID newDevice = ParameterToDeviceID(value);
 	OpenDevice(newDevice, (index == kInputParameter));
 
 	// Update selection in editor
@@ -238,12 +241,13 @@
 {
 	MPT_LOCK_GUARD<mpt::mutex> lock(mutex);
 
-	if(outputDevice.stream != nullptr)
+	if(midiOut.isPortOpen())
 	{
 		// Send MIDI clock
 		if(nextClock < 1)
 		{
-			Pm_WriteShort(outputDevice.stream, Now(), 0xF8);
+			std::vector<unsigned char> message(1, 0xF8);
+			midiOut.sendMessage(&message);
 			double bpm = m_SndFile.GetCurrentBPM();
 			if(bpm != 0.0)
 			{
@@ -254,26 +258,22 @@
 	}
 
 	// We don't do any audio processing here, but we process incoming MIDI events.
-	if(inputDevice.stream == nullptr)
+	if(!midiOut.isPortOpen())
 		return;
 
-	while(Pm_Poll(inputDevice.stream))
+	std::vector<unsigned char> message;
+	while(midiIn.getMessage(&message), !message.empty())
 	{
 		// Read incoming MIDI events.
-		PmEvent buffer;
-		Pm_Read(inputDevice.stream, &buffer, 1);
 
 		// Discard events if bypassed
 		if(IsBypassed())
 			continue;
 
-		mpt::byte message[sizeof(buffer.message)];
-		memcpy(message, &buffer.message, sizeof(message));
-
 		if(!bufferedMessage.empty())
 		{
-			bufferedMessage.push_back(buffer.message);
-			if(buffer.message & 0x80808080)
+			bufferedMessage.insert(bufferedMessage.end(), message.begin(), message.end());
+			if(message.back() == 0xF7)
 			{
 				// End of message found!
 				ReceiveSysex(bufferedMessage.data(), bufferedMessage.size() * sizeof(bufferedMessage[0]));
@@ -280,17 +280,19 @@
 				bufferedMessage.clear();
 			}
 			continue;
-		} else if(message[0] == 0xF0)
+		} else if(message.front() == 0xF0)
 		{
 			// Start of SysEx message...
-			if(message[1] != 0xF7 && message[2] != 0xF7 && message[3] != 0xF7)
-				bufferedMessage.push_back(buffer.message);	// ...but not the end!
+			if(message.back() != 0xF7)
+				bufferedMessage.insert(bufferedMessage.end(), message.begin(), message.end());	// ...but not the end!
 			else
-				ReceiveSysex(message, sizeof(message));
+				ReceiveSysex(&message[0], message.size() * sizeof(message[0]));
 			continue;
 		}
 
-		ReceiveMidi(buffer.message);
+		uint32 msg = 0;
+		memcpy(&msg, &message[0], std::min(message.size(), sizeof(msg)));
+		ReceiveMidi(msg);
 	}
 }
 
@@ -304,9 +306,10 @@
 	nextClock = 0;
 	OpenDevice(inputDevice.index, true);
 	OpenDevice(outputDevice.index, false);
-	if(outputDevice.stream != nullptr)
+	if(midiOut.isPortOpen())
 	{
-		Pm_WriteShort(outputDevice.stream, Now(), 0xFA);	// Start
+		std::vector<unsigned char> message(1, 0xFA);	// Start
+		midiOut.sendMessage(&message);
 	}
 }
 
@@ -316,9 +319,10 @@
 //-----------------------
 {
 	// Suspend MIDI I/O
-	if(outputDevice.stream != nullptr)
+	if(midiOut.isPortOpen())
 	{
-		Pm_WriteShort(outputDevice.stream, Now(), 0xFC);	// Stop
+		std::vector<unsigned char> message(1, 0xFC);	// Stop
+		midiOut.sendMessage(&message);
 	}
 	CloseDevice(inputDevice);
 	CloseDevice(outputDevice);
@@ -330,11 +334,12 @@
 void MidiInOut::PositionChanged()
 //-------------------------------
 {
-	if(outputDevice.stream != nullptr)
+	if(midiOut.isPortOpen())
 	{
-		const PtTimestamp now = Now();
-		Pm_WriteShort(outputDevice.stream, now, 0xFC);	// Stop
-		Pm_WriteShort(outputDevice.stream, now, 0xFA);	// Start
+		std::vector<unsigned char> message;
+		message.push_back(0xFC);	// Stop
+		message.push_back(0xFA);	// Start
+		midiOut.sendMessage(&message);
 	}
 }
 
@@ -343,27 +348,30 @@
 bool MidiInOut::MidiSend(uint32 midiCode)
 //---------------------------------------
 {
-	if(outputDevice.stream == nullptr || IsBypassed())
+	if(!midiOut.isPortOpen() || IsBypassed())
 	{
 		// We need an output device to send MIDI messages to.
 		return true;
 	}
 
-	Pm_WriteShort(outputDevice.stream, Now(), midiCode);
+	std::vector<unsigned char> message(3, 0);
+	memcpy(&message[0], &midiCode, 3);
+	midiOut.sendMessage(&message);
 	return true;
 }
 
 
-bool MidiInOut::MidiSysexSend(const void *message, uint32 /*length*/)
-//-------------------------------------------------------------------
+bool MidiInOut::MidiSysexSend(const void *sysex, uint32 length)
+//-------------------------------------------------------------
 {
-	if(outputDevice.stream == nullptr || IsBypassed())
+	if(!midiOut.isPortOpen() || IsBypassed())
 	{
 		// We need an output device to send MIDI messages to.
 		return true;
 	}
 
-	Pm_WriteSysEx(outputDevice.stream, Now(), const_cast<unsigned char *>(static_cast<const unsigned char *>(message)));
+	std::vector<unsigned char> message(static_cast<const unsigned char *>(sysex), static_cast<const unsigned char *>(sysex) + length);
+	midiOut.sendMessage(&message);
 	return true;
 }
 
@@ -405,20 +413,13 @@
 }
 
 
-static PmTimestamp PtTimeWrapper(void* /*time_info*/)
-//---------------------------------------------------
-{
-	return Pt_Time();
-}
-
-
 // Open a device for input or output.
-void MidiInOut::OpenDevice(PmDeviceID newDevice, bool asInputDevice)
-//------------------------------------------------------------------
+void MidiInOut::OpenDevice(MidiDevice::ID newDevice, bool asInputDevice)
+//----------------------------------------------------------------------
 {
 	MidiDevice &device = asInputDevice ? inputDevice : outputDevice;
 
-	if(device.index == newDevice && device.stream != nullptr)
+	if(device.index == newDevice && device.stream.isPortOpen())
 	{
 		// No need to re-open this device.
 		return;
@@ -427,15 +428,16 @@
 	CloseDevice(device);
 
 	device.index = newDevice;
+	device.stream.closePort();
 
 	if(device.index == kNoDevice)
 	{
 		// Dummy device
-		device = MidiDevice();
+		device.name = "<none>";
 		return;
 	}
 
-	PmError result = pmNoError;
+	device.name = device.GetPortName(newDevice);
 	if(m_isResumed)
 	{
 		// Don't open MIDI devices if we're not processing.
@@ -442,31 +444,20 @@
 		// This has to be done since we receive MIDI events in processReplacing(),
 		// so if no processing is happening, some irrelevant events might be queued until the next processing happens...
 		MPT_LOCK_GUARD<mpt::mutex> lock(mutex);
-		if(asInputDevice)
+		
+		try
 		{
-			result = Pm_OpenInput(&device.stream, newDevice, nullptr, 0, nullptr, nullptr);
-		} else
+			device.stream.openPort(newDevice);
+		} catch(RtMidiError &error)
 		{
-			if(latencyCompensation)
+			device.name = "Unavailable";
+			MidiInOutEditor *editor = dynamic_cast<MidiInOutEditor *>(GetEditor());
+			if(editor != nullptr)
 			{
-				// buffer of 10000 events
-				result = Pm_OpenOutput(&device.stream, newDevice, nullptr, 10000, PtTimeWrapper, nullptr, Util::Round<PtTimestamp>(1000.0 * GetOutputLatency()));
-			} else
-			{
-				result = Pm_OpenOutput(&device.stream, newDevice, nullptr, 0, nullptr, nullptr, 0);
+				Reporting::Error("MIDI device cannot be opened:" + error.getMessage(), "MIDI Input / Output", editor);
 			}
 		}
 	}
-
-	// Update current device name
-	device.name = GetDeviceName(device.index);
-
-	MidiInOutEditor *editor = dynamic_cast<MidiInOutEditor *>(GetEditor());
-	if(result != pmNoError && editor != nullptr)
-	{
-		// Display a warning if the editor is open.
-		Reporting::Error("MIDI device cannot be opened!", "MIDI Input / Output", editor);
-	}
 }
 
 
@@ -474,60 +465,26 @@
 void MidiInOut::CloseDevice(MidiDevice &device)
 //---------------------------------------------
 {
-	if(device.stream != nullptr)
+	if(device.stream.isPortOpen())
 	{
 		MPT_LOCK_GUARD<mpt::mutex> lock(mutex);
-		Pm_Close(device.stream);
-		device.stream = nullptr;
+		device.stream.closePort();
 	}
 }
 
 
 // Get a device name
-const char *MidiInOut::GetDeviceName(PmDeviceID index) const
-//-----------------------------------------------------------
+std::string MidiDevice::GetPortName(MidiDevice::ID port)
+//------------------------------------------------------
 {
-	const PmDeviceInfo *deviceInfo = Pm_GetDeviceInfo(index);
-	if(deviceInfo != nullptr)
-		return deviceInfo->name;
-	else
-		return "Unavailable";
+	std::string portName = stream.getPortName(port);
+#if MPT_OS_WINDOWS
+	// Remove auto-appended port number
+	if(portName.length() >= 2)
+		return portName.substr(0, portName.find_last_of(' '));
+#endif
+	return portName;
 }
 
 
-bool MidiInOut::IsInputDevice(PmDeviceID index) const
-//----------------------------------------------------
-{
-	if(index == kNoDevice)
-		return true;
-
-	const PmDeviceInfo *deviceInfo = Pm_GetDeviceInfo(index);
-	if(deviceInfo != nullptr)
-		return deviceInfo->input != 0;
-	else
-		return false;
-}
-
-
-bool MidiInOut::IsOutputDevice(PmDeviceID index) const
-//----------------------------------------------------
-{
-	if(index == kNoDevice)
-		return true;
-
-	const PmDeviceInfo *deviceInfo = Pm_GetDeviceInfo(index);
-	if(deviceInfo != nullptr)
-		return deviceInfo->output != 0;
-	else
-		return false;
-}
-
-
-PtTimestamp MidiInOut::Now() const
-//--------------------------------
-{
-	return (latencyCompensation ? Pt_Time() : 0);
-}
-
-
 OPENMPT_NAMESPACE_END
Index: plugins/MidiInOut/MidiInOut.h
===================================================================
--- plugins/MidiInOut/MidiInOut.h	(revision 7555)
+++ plugins/MidiInOut/MidiInOut.h	(working copy)
@@ -12,8 +12,7 @@
 
 #include "../../common/mptMutex.h"
 #include "../../soundlib/plugins/PlugInterface.h"
-#include <portmidi/pm_common/portmidi.h>
-#include <portmidi/porttime/porttime.h>
+#include "../../include/rtmidi/RtMidi.h"
 
 
 OPENMPT_NAMESPACE_BEGIN
@@ -24,16 +23,20 @@
 //==============
 {
 public:
-	PmDeviceID index;
-	PortMidiStream *stream;
+	typedef unsigned int ID;
+
+	RtMidi &stream;
 	std::string name;
+	ID index;
 
 public:
-	MidiDevice()
-		: index(-1)	// MidiInOut::kNoDevice
-		, stream(nullptr)
+	MidiDevice(RtMidi &stream)
+		: stream(stream)
 		, name("<none>")
+		, index(ID(-1))	// MidiInOut::kNoDevice
 	{ }
+
+	std::string GetPortName(ID port);
 };
 
 
@@ -62,12 +65,13 @@
 	double nextClock;
 
 	// I/O device settings
+	RtMidiIn midiIn;
+	RtMidiOut midiOut;
 	MidiDevice inputDevice;
 	MidiDevice outputDevice;
 	bool latencyCompensation;
 
 	CString programName;
-	static int numInstances;
 
 public:
 	static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct);
@@ -75,13 +79,13 @@
 	~MidiInOut();
 
 	// Translate a VST parameter to a PortMidi device ID
-	static PmDeviceID ParameterToDeviceID(float value)
+	static MidiDevice::ID ParameterToDeviceID(float value)
 	{
-		return static_cast<PmDeviceID>(value * static_cast<float>(kMaxDevices)) - 1;
+		return static_cast<MidiDevice::ID>(value * static_cast<float>(kMaxDevices)) - 1;
 	}
 
 	// Translate a PortMidi device ID to a VST parameter
-	static float DeviceIDToParameter(PmDeviceID index)
+	static float DeviceIDToParameter(MidiDevice::ID index)
 	{
 		return static_cast<float>(index + 1) / static_cast<float>(kMaxDevices);
 	}
@@ -125,10 +129,6 @@
 #ifdef MODPLUG_TRACKER
 	virtual CString GetDefaultEffectName() { return _T("MIDI Input / Output"); }
 
-	// Cache a range of names, in case one-by-one retrieval would be slow (e.g. when using plugin bridge)
-	virtual void CacheProgramNames(int32, int32) { }
-	virtual void CacheParameterNames(int32, int32) { }
-
 	virtual CString GetParamName(PlugParamIndex param);
 	virtual CString GetParamLabel(PlugParamIndex) { return CString(); }
 	virtual CString GetParamDisplay(PlugParamIndex param);
@@ -155,18 +155,9 @@
 
 protected:
 	// Open a device for input or output.
-	void OpenDevice(PmDeviceID newDevice, bool asInputDevice);
+	void OpenDevice(MidiDevice::ID newDevice, bool asInputDevice);
 	// Close an active device.
 	void CloseDevice(MidiDevice &device);
-	// Get a device name
-	const char *GetDeviceName(PmDeviceID index) const;
-	// Check if the given device is an input device
-	bool IsInputDevice(PmDeviceID index) const;
-	// Check if the given device is an output device
-	bool IsOutputDevice(PmDeviceID index) const;
-
-	// Get current timestamp for sending
-	PtTimestamp Now() const;
 };
 
 
Index: plugins/MidiInOut/MidiInOutEditor.cpp
===================================================================
--- plugins/MidiInOut/MidiInOutEditor.cpp	(revision 7555)
+++ plugins/MidiInOut/MidiInOutEditor.cpp	(working copy)
@@ -14,6 +14,7 @@
 #include "MidiInOutEditor.h"
 #include "../../mptrack/Mptrack.h"
 #include "../../mptrack/resource.h"
+#include "../../include/rtmidi/RtMidi.h"
 
 
 OPENMPT_NAMESPACE_BEGIN
@@ -75,32 +76,38 @@
 	int selectOutputItem = 0;
 	MidiInOut &plugin = static_cast<MidiInOut &>(m_VstPlugin);
 
-	const PmDeviceInfo *device;
-	CString deviceName;
-
-	// Go through all PortMidi devices
-	for(PmDeviceID i = 0; (device = Pm_GetDeviceInfo(i)) != nullptr; i++)
+	// Go through all RtMidi devices
+	unsigned int ports = plugin.midiIn.getPortCount();
+	std::string portName;
+	for(unsigned int i = 0; i < ports; i++)
 	{
-		if(device->input)
+		try
 		{
-			// We can actually receive MIDI data on this device.
-			deviceName = theApp.GetFriendlyMIDIPortName(device->name, true) + _T(" [") + CString(device->interf) + _T("]");
-			int result = m_inputCombo.AddString(deviceName);
+			portName = theApp.GetFriendlyMIDIPortName(plugin.inputDevice.GetPortName(i).c_str(), true);
+			int result = m_inputCombo.AddString(portName.c_str());
 			m_inputCombo.SetItemData(result, i);
 
 			if(result != CB_ERR && i == plugin.inputDevice.index)
 				selectInputItem = result;
 		}
+		catch(RtMidiError &)
+		{
+		}
+	}
 
-		if(device->output)
+	ports = plugin.midiOut.getPortCount();
+	for(unsigned int i = 0; i < ports; i++)
+	{
+		try
 		{
-			// We can actually output MIDI data on this device.
-			deviceName = theApp.GetFriendlyMIDIPortName(device->name, false) + _T(" [") + CString(device->interf) + _T("]");
-			int result = m_outputCombo.AddString(deviceName);
+			portName = theApp.GetFriendlyMIDIPortName(plugin.outputDevice.GetPortName(i).c_str(), false);
+			int result = m_outputCombo.AddString(portName.c_str());
 			m_outputCombo.SetItemData(result, i);
 
 			if(result != CB_ERR && i == plugin.outputDevice.index)
 				selectOutputItem = result;
+		} catch(RtMidiError &)
+		{
 		}
 	}
 
@@ -113,13 +120,13 @@
 
 
 // Refresh current input / output device in GUI
-void MidiInOutEditor::SetCurrentDevice(CComboBox &combo, PmDeviceID device)
-//-------------------------------------------------------------------------
+void MidiInOutEditor::SetCurrentDevice(CComboBox &combo, MidiDevice::ID device)
+//-----------------------------------------------------------------------------
 {
 	int items = combo.GetCount();
 	for(int i = 0; i < items; i++)
 	{
-		if(static_cast<PmDeviceID>(combo.GetItemData(i)) == device)
+		if(static_cast<MidiDevice::ID>(combo.GetItemData(i)) == device)
 		{
 			combo.SetCurSel(i);
 			break;
@@ -132,7 +139,7 @@
 //------------------------------------------------------------------------------
 {
 	// Update device ID and notify plugin.
-	PmDeviceID newDevice = static_cast<PmDeviceID>(combo.GetItemData(combo.GetCurSel()));
+	MidiDevice::ID newDevice = static_cast<MidiDevice::ID>(combo.GetItemData(combo.GetCurSel()));
 	plugin.SetParameter(param, MidiInOut::DeviceIDToParameter(newDevice));
 	plugin.AutomateParameter(param);
 }
Index: plugins/MidiInOut/MidiInOutEditor.h
===================================================================
--- plugins/MidiInOut/MidiInOutEditor.h	(revision 7555)
+++ plugins/MidiInOut/MidiInOutEditor.h	(working copy)
@@ -13,7 +13,6 @@
 #ifdef MODPLUG_TRACKER
 
 #include "../../mptrack/AbstractVstEditor.h"
-#include <portmidi/pm_common/portmidi.h>
 
 OPENMPT_NAMESPACE_BEGIN
 
@@ -32,7 +31,7 @@
 	MidiInOutEditor(MidiInOut &plugin);
 
 	// Refresh current input / output device in GUI
-	void SetCurrentDevice(bool asInputDevice, PmDeviceID device)
+	void SetCurrentDevice(bool asInputDevice, MidiDevice::ID device)
 	{
 		CComboBox &combo = asInputDevice ? m_inputCombo : m_outputCombo;
 		SetCurrentDevice(combo, device);
@@ -47,7 +46,7 @@
 	// Update lists of available input / output devices
 	void PopulateLists();
 	// Refresh current input / output device in GUI
-	void SetCurrentDevice(CComboBox &combo, PmDeviceID device);
+	void SetCurrentDevice(CComboBox &combo, MidiDevice::ID device);
 
 	virtual void DoDataExchange(CDataExchange* pDX);
 
