View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0000843 | OpenMPT | Plugins / VST | public | 2016-07-31 22:49 | 2017-07-24 11:37 |
Reporter | Saga Musix | Assigned To | Saga Musix | ||
Priority | high | Severity | crash | Reproducibility | random |
Status | resolved | Resolution | fixed | ||
Product Version | OpenMPT 1.26.03.00 / libopenmpt 0.2-beta18 (upgrade first) | ||||
Target Version | OpenMPT 1.27.01.00 / libopenmpt 0.3.1 (upgrade first) | Fixed in Version | OpenMPT 1.27.01.00 / libopenmpt 0.3.1 (upgrade first) | ||
Summary | 0000843: Sporadic deadlocks in MIDI I/O | ||||
Description | I keep experiencing random deadlocks in midiStreamClose when using the restart playback button in the main toolbar while the MIDI I/O plugin is in use. This could mean that threading is not implemented correctly on our or PortMidi's side, or my MIDI interface driver is buggy. Devices are opened and closed in the main thread when stopping or resuming playback, but the relevant code is guarded by a mutex. | ||||
Tags | No tags attached. | ||||
Attached Files | rtmidi.patch (20,752 bytes)
Index: mptrack/mptrack_10.vcxproj =================================================================== --- mptrack/mptrack_10.vcxproj (revision 7100) +++ mptrack/mptrack_10.vcxproj (working copy) @@ -750,6 +750,7 @@ <ClCompile Include="..\common\serialization_utils.cpp" /> <ClCompile Include="..\common\typedefs.cpp" /> <ClCompile Include="..\common\version.cpp" /> + <ClCompile Include="..\include\rtmidi\RtMidi.cpp" /> <ClCompile Include="..\pluginBridge\BridgeWrapper.cpp" /> <ClCompile Include="..\plugins\MidiInOut\MidiInOut.cpp" /> <ClCompile Include="..\plugins\MidiInOut\MidiInOutEditor.cpp" /> @@ -1010,6 +1011,7 @@ <ClInclude Include="..\common\version.h" /> <ClInclude Include="..\common\versionNumber.h" /> <ClInclude Include="..\common\WriteMemoryDump.h" /> + <ClInclude Include="..\include\rtmidi\RtMidi.h" /> <ClInclude Include="..\pluginBridge\AEffectWrapper.h" /> <ClInclude Include="..\pluginBridge\BridgeCommon.h" /> <ClInclude Include="..\pluginBridge\BridgeWrapper.h" /> Index: mptrack/mptrack_10.vcxproj.filters =================================================================== --- mptrack/mptrack_10.vcxproj.filters (revision 7100) +++ mptrack/mptrack_10.vcxproj.filters (working copy) @@ -652,6 +652,9 @@ <ClCompile Include="BuildVariants.cpp"> <Filter>Source Files\mptrack</Filter> </ClCompile> + <ClCompile Include="..\include\rtmidi\RtMidi.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="..\soundlib\Loaders.h"> @@ -1281,6 +1284,9 @@ <ClInclude Include="BuildVariants.h"> <Filter>Header Files\mptrack</Filter> </ClInclude> + <ClInclude Include="..\include\rtmidi\RtMidi.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="res\bitmap1.bmp"> Index: plugins/MidiInOut/MidiInOut.cpp =================================================================== --- plugins/MidiInOut/MidiInOut.cpp (revision 7100) +++ 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(); + int inID = file.ReadInt32LE(); uint32 inStrSize = file.ReadUint32LE(); - PmDeviceID outID = file.ReadUint32LE(); + int outID = file.ReadInt32LE(); 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)) + 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)) + 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); + int newDevice = ParameterToDeviceID(value); OpenDevice(newDevice, (index == kInputParameter)); // Update selection in editor @@ -237,12 +240,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) { @@ -253,26 +257,20 @@ } // 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])); @@ -279,17 +277,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); } } @@ -303,9 +303,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); } } @@ -315,9 +316,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); @@ -329,11 +331,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); } } @@ -342,27 +345,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; } @@ -376,7 +382,7 @@ Resume(); } - for(uint8 mc = 0; mc < CountOf(m_MidiCh); mc++) //all midi chans + for(auto mc = 0; mc < CountOf(m_MidiCh); mc++) //all midi chans { PlugInstrChannel &channel = m_MidiCh[mc]; channel.ResetProgram(); @@ -384,7 +390,7 @@ MidiPitchBend(mc, EncodePitchBendParam(MIDIEvents::pitchBendCentre)); // centre pitch bend MidiSend(MIDIEvents::CC(MIDIEvents::MIDICC_AllSoundOff, mc, 0)); // all sounds off - for(size_t i = 0; i < CountOf(channel.noteOnMap); i++) //all notes + for(auto i = 0; i < CountOf(channel.noteOnMap); i++) //all notes { for(CHANNELINDEX c = 0; c < CountOf(channel.noteOnMap[i]); c++) { @@ -404,20 +410,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(int 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; @@ -426,15 +425,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. @@ -441,31 +441,22 @@ // 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); + // Display a warning if the editor is open. + 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); - } } @@ -473,33 +464,25 @@ 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(int 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; } -PtTimestamp MidiInOut::Now() const -//-------------------------------- -{ - return (latencyCompensation ? Pt_Time() : 0); -} - - OPENMPT_NAMESPACE_END Index: plugins/MidiInOut/MidiInOut.h =================================================================== --- plugins/MidiInOut/MidiInOut.h (revision 7100) +++ plugins/MidiInOut/MidiInOut.h (working copy) @@ -12,10 +12,10 @@ #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 +24,18 @@ //============== { public: - PmDeviceID index; - PortMidiStream *stream; + RtMidi &stream; std::string name; + int index; public: - MidiDevice() - : index(-1) // MidiInOut::kNoDevice - , stream(nullptr) + MidiDevice(RtMidi &stream) + : stream(stream) , name("<none>") + , index(-1) // MidiInOut::kNoDevice { } + + std::string GetPortName(int port); }; @@ -62,12 +64,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 +78,13 @@ ~MidiInOut(); // Translate a VST parameter to a PortMidi device ID - static PmDeviceID ParameterToDeviceID(float value) + static int ParameterToDeviceID(float value) { - return static_cast<PmDeviceID>(value * static_cast<float>(kMaxDevices)) - 1; + return static_cast<int>(value * static_cast<float>(kMaxDevices)) - 1; } // Translate a PortMidi device ID to a VST parameter - static float DeviceIDToParameter(PmDeviceID index) + static float DeviceIDToParameter(int index) { return static_cast<float>(index + 1) / static_cast<float>(kMaxDevices); } @@ -154,14 +157,9 @@ protected: // Open a device for input or output. - void OpenDevice(PmDeviceID newDevice, bool asInputDevice); + void OpenDevice(int newDevice, bool asInputDevice); // Close an active device. void CloseDevice(MidiDevice &device); - // Get a device name - const char *GetDeviceName(PmDeviceID index) const; - - // Get current timestamp for sending - PtTimestamp Now() const; }; Index: plugins/MidiInOut/MidiInOutEditor.cpp =================================================================== --- plugins/MidiInOut/MidiInOutEditor.cpp (revision 7100) +++ plugins/MidiInOut/MidiInOutEditor.cpp (working copy) @@ -13,6 +13,7 @@ #include "MidiInOut.h" #include "MidiInOutEditor.h" #include "../../mptrack/resource.h" +#include "../../include/rtmidi/RtMidi.h" OPENMPT_NAMESPACE_BEGIN @@ -74,32 +75,37 @@ int selectOutputItem = 0; MidiInOut &plugin = static_cast<MidiInOut &>(m_VstPlugin); - const PmDeviceInfo *device; - - // 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++) { - std::string deviceName = std::string(device->name) + std::string(" [") + std::string(device->interf) + std::string("]"); - // We could make use of Pm_GetDefaultInputDeviceID / Pm_GetDefaultOutputDeviceID here, but is it useful to show those actually? - - if(device->input) + try { - // We can actually receive MIDI data on this device. - int result = m_inputCombo.AddString(deviceName.c_str()); + portName = plugin.inputDevice.GetPortName(i); + 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 &error) + { } + } - 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. - int result = m_outputCombo.AddString(deviceName.c_str()); + portName = plugin.outputDevice.GetPortName(i); + 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 &error) + { } } @@ -112,13 +118,13 @@ // Refresh current input / output device in GUI -void MidiInOutEditor::SetCurrentDevice(CComboBox &combo, PmDeviceID device) -//------------------------------------------------------------------------- +void MidiInOutEditor::SetCurrentDevice(CComboBox &combo, int device) +//------------------------------------------------------------------ { int items = combo.GetCount(); for(int i = 0; i < items; i++) { - if(static_cast<PmDeviceID>(combo.GetItemData(i)) == device) + if(static_cast<int>(combo.GetItemData(i)) == device) { combo.SetCurSel(i); break; @@ -131,7 +137,7 @@ //------------------------------------------------------------------------------ { // Update device ID and notify plugin. - PmDeviceID newDevice = static_cast<PmDeviceID>(combo.GetItemData(combo.GetCurSel())); + int newDevice = static_cast<int>(combo.GetItemData(combo.GetCurSel())); plugin.SetParameter(param, MidiInOut::DeviceIDToParameter(newDevice)); plugin.AutomateParameter(param); } Index: plugins/MidiInOut/MidiInOutEditor.h =================================================================== --- plugins/MidiInOut/MidiInOutEditor.h (revision 7100) +++ 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, int 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, int device); virtual void DoDataExchange(CDataExchange* pDX); RtMidi-2.patch (24,162 bytes)
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); | ||||
Has the bug occurred in previous versions? | Yes | ||||
Tested code revision (in case you know it) | |||||
has duplicate | 0000994 | closed | Crash when trying to mute a MIDI output |
So far, running my own builds with RtMidi (instead of PortMidi) did not yield any deadlocks for a long while. There might be a problem in PortMidi. If we wanted to switch, we would have to re-implement PortMidi's latency compensation. Quick-and-dirty RtMidi replacement patch has been added to the issue. |
|
PortMidi also randomly crashes e.g. in winmm_write_flush, which I tried working around previously, but there are apparently more ways it can crash: https://forum.openmpt.org/index.php?topic=5784.0 |
|
Updated patch: Moved Midi In to callback function - might be more desirable as per https://github.com/thestk/rtmidi/issues/51#issuecomment-138185164 RtMidi-3.patch (29,131 bytes)
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,27 +20,27 @@ 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; + } } MidiInOut::MidiInOut(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct) : IMidiPlugin(factory, sndFile, mixStruct) - , latencyCompensation(true) - , programName(_T("Default")) + , m_latencyCompensation(true) + , m_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(); - } } @@ -93,7 +86,7 @@ size_t MidiInOut::GetChunk(char *(&chunk), bool /*isBank*/) //--------------------------------------------------------- { - const std::string programName8 = mpt::ToCharset(mpt::CharsetUTF8, programName); + const std::string programName8 = mpt::ToCharset(mpt::CharsetUTF8, m_programName); const std::string inputName8 = mpt::ToCharset(mpt::CharsetUTF8, mpt::CharsetLocale, inputDevice.name); const std::string outputName8 = mpt::ToCharset(mpt::CharsetUTF8, mpt::CharsetLocale, outputDevice.name); @@ -106,13 +99,13 @@ mpt::IO::WriteIntLE<uint32>(s, static_cast<uint32>(inputDevice.name.size())); mpt::IO::WriteIntLE<uint32>(s, outputDevice.index); mpt::IO::WriteIntLE<uint32>(s, static_cast<uint32>(outputDevice.name.size())); - mpt::IO::WriteIntLE<uint32>(s, latencyCompensation); + mpt::IO::WriteIntLE<uint32>(s, m_latencyCompensation); mpt::IO::WriteRaw(s, programName8.c_str(), programName8.size()); mpt::IO::WriteRaw(s, inputName8.c_str(), inputName8.size()); mpt::IO::WriteRaw(s, outputName8.c_str(), outputName8.size()); - chunkData = s.str(); - chunk = const_cast<char *>(chunkData.c_str()); - return chunkData.size(); + m_chunkData = s.str(); + chunk = const_cast<char *>(m_chunkData.c_str()); + return m_chunkData.size(); } @@ -127,28 +120,33 @@ 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; + m_latencyCompensation = file.ReadUint32LE() != 0; std::string s; file.ReadString<mpt::String::maybeNullTerminated>(s, nameStrSize); - programName = mpt::ToCString(mpt::CharsetUTF8, s); + m_programName = mpt::ToCString(mpt::CharsetUTF8, s); 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 @@ -236,61 +239,59 @@ void MidiInOut::Process(float *, float *, uint32 numFrames) //--------------------------------------------------------- { - MPT_LOCK_GUARD<mpt::mutex> lock(mutex); + MPT_LOCK_GUARD<mpt::mutex> lock(m_mutex); - if(outputDevice.stream != nullptr) + if(midiOut.isPortOpen()) { // Send MIDI clock - if(nextClock < 1) + if(m_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) { - nextClock += 2.5 * m_SndFile.GetSampleRate() / bpm; + m_nextClock += 2.5 * m_SndFile.GetSampleRate() / bpm; } } - nextClock -= numFrames; + m_nextClock -= numFrames; } +} - // We don't do any audio processing here, but we process incoming MIDI events. - if(inputDevice.stream == nullptr) - return; - while(Pm_Poll(inputDevice.stream)) +void MidiInOut::InputCallback(double /*deltatime*/, std::vector<unsigned char> &message) +//-------------------------------------------------------------------------------------- +{ + // We will check the bypass status before passing on the message, and not before entering the function, + // because otherwise we might read garbage if we toggle bypass status in the middle of a SysEx message. + bool isBypassed = IsBypassed(); + if(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()) + return; + } else if(!m_bufferedMessage.empty()) + { + // SysEx message (continued) + m_bufferedMessage.insert(m_bufferedMessage.end(), message.begin(), message.end()); + if(message.back() == 0xF7) { - bufferedMessage.push_back(buffer.message); - if(buffer.message & 0x80808080) - { - // End of message found! - ReceiveSysex(bufferedMessage.data(), bufferedMessage.size() * sizeof(bufferedMessage[0])); - bufferedMessage.clear(); - } - continue; - } else if(message[0] == 0xF0) - { - // Start of SysEx message... - if(message[1] != 0xF7 && message[2] != 0xF7 && message[3] != 0xF7) - bufferedMessage.push_back(buffer.message); // ...but not the end! - else - ReceiveSysex(message, sizeof(message)); - continue; + // End of message found! + if(!isBypassed) + ReceiveSysex(m_bufferedMessage.data(), m_bufferedMessage.size()); + m_bufferedMessage.clear(); } - - ReceiveMidi(buffer.message); + } else if(message.front() == 0xF0) + { + // Start of SysEx message... + if(message.back() != 0xF7) + m_bufferedMessage.insert(m_bufferedMessage.end(), message.begin(), message.end()); // ...but not the end! + else if(!isBypassed) + ReceiveSysex(message.data(), message.size()); + } else if(!isBypassed) + { + // Regular message + uint32 msg = 0; + memcpy(&msg, message.data(), std::min(message.size(), sizeof(msg))); + ReceiveMidi(msg); } } @@ -301,12 +302,13 @@ { // Resume MIDI I/O m_isResumed = true; - nextClock = 0; + m_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 +318,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 +333,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 +347,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 +412,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,46 +427,41 @@ CloseDevice(device); device.index = newDevice; + device.stream.closePort(); if(device.index == kNoDevice) { // Dummy device - device = MidiDevice(); + device.name = "<none>"; return; } - PmError result = pmNoError; - if(m_isResumed) + device.name = device.GetPortName(newDevice); + //if(m_isResumed) { // Don't open MIDI devices if we're not processing. // 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) + MPT_LOCK_GUARD<mpt::mutex> lock(m_mutex); + + try { - result = Pm_OpenInput(&device.stream, newDevice, nullptr, 0, nullptr, nullptr); - } else + device.stream.openPort(newDevice); + if(asInputDevice) + { + midiIn.setCallback(InputCallback, this); + midiIn.ignoreTypes(false, true, true); + } + } 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 +469,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; + MPT_LOCK_GUARD<mpt::mutex> lock(m_mutex); + 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); }; @@ -56,18 +59,21 @@ kMaxDevices = 65536, // Should be a power of 2 to avoid rounding errors. }; - std::string chunkData; // Storage for GetChunk - std::vector<uint32> bufferedMessage; // For receiving SysEx messages - mpt::mutex mutex; - double nextClock; + std::string m_chunkData; // Storage for GetChunk + std::vector<unsigned char> m_bufferedMessage; // For receiving SysEx messages + mpt::mutex m_mutex; + double m_nextClock; // I/O device settings + RtMidiIn midiIn; + RtMidiOut midiOut; MidiDevice inputDevice; MidiDevice outputDevice; - bool latencyCompensation; + bool m_latencyCompensation; - CString programName; - static int numInstances; +#ifdef MODPLUG_TRACKER + CString m_programName; +#endif public: static IMixPlugin* Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct); @@ -75,13 +81,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,16 +131,12 @@ #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); - virtual CString GetCurrentProgramName() { return programName; } - virtual void SetCurrentProgramName(const CString &name) { programName = name; } - virtual CString GetProgramName(int32) { return programName; } + virtual CString GetCurrentProgramName() { return m_programName; } + virtual void SetCurrentProgramName(const CString &name) { m_programName = name; } + virtual CString GetProgramName(int32) { return m_programName; } virtual CString GetPluginVendor() { return _T("OpenMPT Project"); } virtual bool HasEditor() const { return true; } @@ -155,18 +157,12 @@ 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; + static void InputCallback(double deltatime, std::vector<unsigned char> *message, void *userData) { static_cast<MidiInOut *>(userData)->InputCallback(deltatime, *message); } + void InputCallback(double deltatime, std::vector<unsigned char> &message); }; 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 @@ -51,7 +52,7 @@ //-------------------------------------------- { Create(IDD_MIDI_IO_PLUGIN, parent); - m_latencyCheck.SetCheck(static_cast<MidiInOut &>(m_VstPlugin).latencyCompensation ? BST_CHECKED : BST_UNCHECKED); + m_latencyCheck.SetCheck(static_cast<MidiInOut &>(m_VstPlugin).m_latencyCompensation ? BST_CHECKED : BST_UNCHECKED); PopulateLists(); return CAbstractVstEditor::OpenEditor(parent); } @@ -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); } @@ -157,7 +164,7 @@ { MidiInOut &plugin = static_cast<MidiInOut &>(m_VstPlugin); plugin.CloseDevice(plugin.outputDevice); - plugin.latencyCompensation = (m_latencyCheck.GetCheck() != BST_UNCHECKED); + plugin.m_latencyCompensation = (m_latencyCheck.GetCheck() != BST_UNCHECKED); plugin.OpenDevice(plugin.outputDevice.index, false); } 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); |
|
r7573 switches from PortMidi to RtMidi. |
|
Date Modified | Username | Field | Change |
---|---|---|---|
2016-07-31 22:49 | Saga Musix | New Issue | |
2016-07-31 22:52 | Saga Musix | Description Updated | |
2016-07-31 22:53 | Saga Musix | Description Updated | |
2016-09-11 14:39 | Saga Musix | Note Added: 0002656 | |
2016-09-11 14:40 | Saga Musix | File Added: rtmidi.patch | |
2016-09-11 14:40 | Saga Musix | Note Edited: 0002656 | |
2016-11-20 17:48 | Saga Musix | Category | VST => Plugins (VST) |
2016-11-20 17:48 | Saga Musix | Category | Plugins (VST) => Plugins / VST |
2017-02-05 01:40 | Saga Musix | Note Added: 0002862 | |
2017-02-05 01:43 | Saga Musix | Priority | normal => high |
2017-02-05 01:43 | Saga Musix | Severity | minor => crash |
2017-02-06 00:23 | Saga Musix | File Added: RtMidi-2.patch | |
2017-02-06 00:24 | Saga Musix | Assigned To | => Saga Musix |
2017-02-06 00:24 | Saga Musix | Status | new => assigned |
2017-02-06 00:24 | Saga Musix | Target Version | => OpenMPT 1.27.01.00 / libopenmpt 0.3.1 (upgrade first) |
2017-02-06 22:01 | Saga Musix | File Added: RtMidi-3.patch | |
2017-02-06 22:01 | Saga Musix | Note Added: 0002864 | |
2017-02-09 01:19 | Saga Musix | Status | assigned => resolved |
2017-02-09 01:19 | Saga Musix | Resolution | open => fixed |
2017-02-09 01:19 | Saga Musix | Fixed in Version | => OpenMPT 1.27.01.00 / libopenmpt 0.3.1 (upgrade first) |
2017-02-09 01:19 | Saga Musix | Note Added: 0002870 | |
2017-07-24 11:37 | Saga Musix | Relationship added | has duplicate 0000994 |