Index: mptrack/mptrack_10.vcxproj =================================================================== --- mptrack/mptrack_10.vcxproj (revision 7100) +++ mptrack/mptrack_10.vcxproj (working copy) @@ -750,6 +750,7 @@ + @@ -1010,6 +1011,7 @@ + Index: mptrack/mptrack_10.vcxproj.filters =================================================================== --- mptrack/mptrack_10.vcxproj.filters (revision 7100) +++ mptrack/mptrack_10.vcxproj.filters (working copy) @@ -652,6 +652,9 @@ Source Files\mptrack + + Source Files + @@ -1281,6 +1284,9 @@ Header Files\mptrack + + Header Files + 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(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(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 lock(mutex); - if(outputDevice.stream != nullptr) + if(midiOut.isPortOpen()) { // Send MIDI clock if(nextClock < 1) { - Pm_WriteShort(outputDevice.stream, Now(), 0xF8); + std::vector 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 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 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 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 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 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(static_cast(message))); + std::vector message(static_cast(sysex), static_cast(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 = ""; 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 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(GetEditor()); + if(editor != nullptr) { - // buffer of 10000 events - result = Pm_OpenOutput(&device.stream, newDevice, nullptr, 10000, PtTimeWrapper, nullptr, Util::Round(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(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 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 -#include +#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("") + , 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(value * static_cast(kMaxDevices)) - 1; + return static_cast(value * static_cast(kMaxDevices)) - 1; } // Translate a PortMidi device ID to a VST parameter - static float DeviceIDToParameter(PmDeviceID index) + static float DeviceIDToParameter(int index) { return static_cast(index + 1) / static_cast(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(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(combo.GetItemData(i)) == device) + if(static_cast(combo.GetItemData(i)) == device) { combo.SetCurSel(i); break; @@ -131,7 +137,7 @@ //------------------------------------------------------------------------------ { // Update device ID and notify plugin. - PmDeviceID newDevice = static_cast(combo.GetItemData(combo.GetCurSel())); + int newDevice = static_cast(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 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);