From: <sag...@us...> - 2014-03-17 02:56:40
|
Revision: 3893 http://sourceforge.net/p/modplug/code/3893 Author: saga-games Date: 2014-03-17 02:56:32 +0000 (Mon, 17 Mar 2014) Log Message: ----------- [Imp] More plugin bridge improvements (SynthEdit plugs work, and time info caching) Modified Paths: -------------- trunk/OpenMPT/pluginBridge/AEffectWrapper.h trunk/OpenMPT/pluginBridge/Bridge.cpp trunk/OpenMPT/pluginBridge/Bridge.h trunk/OpenMPT/pluginBridge/BridgeCommon.h trunk/OpenMPT/pluginBridge/BridgeWrapper.cpp trunk/OpenMPT/plugins/MidiInOut/MidiInOut.vcxproj.filters trunk/OpenMPT/plugins/MidiInOut/MidiInOutEditor.cpp trunk/OpenMPT/plugins/common/CheckBox.h trunk/OpenMPT/plugins/common/ComboBox.h trunk/OpenMPT/plugins/common/Label.h trunk/OpenMPT/plugins/common/Window.h trunk/OpenMPT/plugins/common/WindowBase.h Modified: trunk/OpenMPT/pluginBridge/AEffectWrapper.h =================================================================== --- trunk/OpenMPT/pluginBridge/AEffectWrapper.h 2014-03-16 23:25:31 UTC (rev 3892) +++ trunk/OpenMPT/pluginBridge/AEffectWrapper.h 2014-03-17 02:56:32 UTC (rev 3893) @@ -129,16 +129,35 @@ // Translate bridge format (void *ptr) back to VSTEvents struct (placed in data vector) static void TranslateBridgeToVSTEvents(std::vector<char> &data, void *ptr) { - int32_t numEvents = *static_cast<const int32_t *>(ptr); + const int32_t numEvents = *static_cast<const int32_t *>(ptr); - data.resize(sizeof(VstInt32) + sizeof(VstIntPtr) + sizeof(VstEvent *) * numEvents, 0); - VstEvents *events = reinterpret_cast<VstEvents *>(&data[0]); - events->numEvents = numEvents; + const size_t headerSize = sizeof(VstInt32) + sizeof(VstIntPtr) + sizeof(VstEvent *) * numEvents; + data.reserve(headerSize + sizeof(VstEvent) * numEvents); + data.resize(headerSize, 0); - // Write pointers + // Copy over event data (this is required for dumb SynthEdit plugins that don't copy over the event data during effProcessEvents) char *offset = static_cast<char *>(ptr) + sizeof(int32_t); for(int32_t i = 0; i < numEvents; i++) { + VstEvent *event = reinterpret_cast<VstEvent *>(offset); + data.insert(data.end(), offset, offset + event->byteSize); + offset += event->byteSize; + + if(event->type == kVstSysExType) + { + // Copy over sysex dump + VstMidiSysexEvent *sysExEvent = reinterpret_cast<VstMidiSysexEvent *>(event); + data.insert(data.end(), offset, offset + sysExEvent->dumpBytes); + offset += sysExEvent->dumpBytes; + } + } + + // Write pointers + VstEvents *events = reinterpret_cast<VstEvents *>(&data[0]); + events->numEvents = numEvents; + offset = &data[headerSize]; + for(int32_t i = 0; i < numEvents; i++) + { events->events[i] = reinterpret_cast<VstEvent *>(offset); offset += events->events[i]->byteSize; if(events->events[i]->type == kVstSysExType) Modified: trunk/OpenMPT/pluginBridge/Bridge.cpp =================================================================== --- trunk/OpenMPT/pluginBridge/Bridge.cpp 2014-03-16 23:25:31 UTC (rev 3892) +++ trunk/OpenMPT/pluginBridge/Bridge.cpp 2014-03-17 02:56:32 UTC (rev 3893) @@ -15,6 +15,7 @@ // => sigThreadExit might already be an invalid handle the time it arrives in the thread // Fix deadlocks in some plugin GUIs (Synth1 sliders, triggering many notes through the M1 GUI, Electri-Q program change) // Ability to put all plugins (or all instances of the same plugin) in the same container. Necessary for plugins like SideKick v3. +// jBridged Rez3 GUI breaks // Low priority: // Speed up things like consecutive calls to CVstPlugin::GetFormattedProgramName by a custom opcode @@ -466,8 +467,9 @@ case effProcessEvents: // VstEvents* in [ptr] - TranslateBridgeToVSTEvents(extraData, ptr); - ptr = &extraData[0]; + TranslateBridgeToVSTEvents(eventCache, ptr); + ptr = &eventCache[0]; + break; case effOfflineNotify: @@ -710,16 +712,22 @@ { assert(sharedMem.processMem.Good()); ProcessMsg *msg = static_cast<ProcessMsg *>(sharedMem.processMem.view); + size_t numPtrs = msg->numInputs + msg->numOutputs; samplePointers.resize(numPtrs, 0); - buf_t *offset = reinterpret_cast<buf_t *>(msg + 1); - for(size_t i = 0; i < numPtrs; i++) + + if(numPtrs) { - samplePointers[i] = offset; - offset += msg->sampleFrames; + buf_t *offset = reinterpret_cast<buf_t *>(msg + 1); + for(size_t i = 0; i < numPtrs; i++) + { + samplePointers[i] = offset; + offset += msg->sampleFrames; + } + inPointers = reinterpret_cast<buf_t **>(&samplePointers[0]); + outPointers = reinterpret_cast<buf_t **>(&samplePointers[msg->numInputs]); } - inPointers = reinterpret_cast<buf_t **>(&samplePointers[0]); - outPointers = reinterpret_cast<buf_t **>(&samplePointers[msg->numInputs]); + return msg->sampleFrames; } @@ -727,6 +735,8 @@ // Send a message to the host. VstIntPtr PluginBridge::DispatchToHost(VstInt32 opcode, VstInt32 index, VstIntPtr value, void *ptr, float opt) { + const bool processing = InterlockedExchangeAdd(&isProcessing, 0) != 0; + std::vector<char> dispatchData(sizeof(DispatchMsg), 0); int64_t ptrOut = 0; char *ptrC = static_cast<char *>(ptr); @@ -742,6 +752,15 @@ case audioMasterGetTime: // VstTimeInfo* in [return value] + if(processing) + { + // During processing, read the cached time info if possible + VstTimeInfo &timeInfo = static_cast<ProcessMsg *>(sharedMem.processMem.view)->timeInfo; + if((timeInfo.flags & value) == value) + { + return reinterpret_cast<VstIntPtr>(&static_cast<ProcessMsg *>(sharedMem.processMem.view)->timeInfo); + } + } ptrOut = sizeof(VstTimeInfo); break; @@ -765,7 +784,7 @@ MPT_FALLTHROUGH; case audioMasterIOChanged: // We need to be sure that the new values are known to the master. - if(InterlockedExchangeAdd(&isProcessing, 0) == 0) + if(!processing) { UpdateEffectStruct(); CreateProcessingFile(dispatchData); @@ -906,8 +925,13 @@ { case audioMasterGetTime: // VstTimeInfo* in [return value] - memcpy(&host2PlugMem.timeInfo, extraData, sizeof(VstTimeInfo)); - return ToVstPtr<VstTimeInfo>(&host2PlugMem.timeInfo); + if(sharedMem.processMem.Good()) + { + VstTimeInfo *timeInfo = &static_cast<ProcessMsg *>(sharedMem.processMem.view)->timeInfo; + memcpy(timeInfo, extraData, sizeof(VstTimeInfo)); + return ToVstPtr<VstTimeInfo>(timeInfo); + } + return 0; case audioMasterGetOutputSpeakerArrangement: case audioMasterGetInputSpeakerArrangement: Modified: trunk/OpenMPT/pluginBridge/Bridge.h =================================================================== --- trunk/OpenMPT/pluginBridge/Bridge.h 2014-03-16 23:25:31 UTC (rev 3892) +++ trunk/OpenMPT/pluginBridge/Bridge.h 2014-03-17 02:56:32 UTC (rev 3893) @@ -29,9 +29,9 @@ union { VstSpeakerArrangement speakerArrangement; - VstTimeInfo timeInfo; char name[256]; } host2PlugMem; + std::vector<char> eventCache; // Cached VST (MIDI) events // Shared memory SharedMem sharedMem; Modified: trunk/OpenMPT/pluginBridge/BridgeCommon.h =================================================================== --- trunk/OpenMPT/pluginBridge/BridgeCommon.h 2014-03-16 23:25:31 UTC (rev 3892) +++ trunk/OpenMPT/pluginBridge/BridgeCommon.h 2014-03-17 02:56:32 UTC (rev 3893) @@ -167,6 +167,7 @@ int32_t numInputs; int32_t numOutputs; int32_t sampleFrames; + VstTimeInfo timeInfo; // Input and output buffers follow ProcessMsg(ProcessMsg::ProcessType processType, int32_t numInputs, int32_t numOutputs, int32_t sampleFrames) : @@ -196,10 +197,11 @@ // Message life-cycle enum BridgeMessageStatus { - empty = 0, - sent, - received, - done, + empty = 0, // Slot is usable + prepared, // Slot got acquired and is being prepared + sent, // Slot is ready to be sent + received, // Slot is being handled + done, // Slot got handled }; uint32_t status; // See BridgeMessageStatus @@ -361,11 +363,9 @@ class SharedMem { public: - //std::map<winhandle_t, SignalSlot *> threadMap; // Map thread IDs to signals - // Signals for host <-> bridge communication Signal sigToHost, sigToBridge, sigProcess; - // Signals for internal communication (wake up waiting threads). Ack() => OK, Send() => Failure + // Signals for internal communication (wake up waiting threads). Confirm() => OK, Send() => Failure Signal ackSignals[MsgQueue::queueSize]; HANDLE otherProcess; // Handle of "other" process (host handle in the bridge and vice versa) @@ -400,18 +400,22 @@ // Copy a message to shared memory and return relative position. BridgeMessage *CopyToSharedMemory(const BridgeMessage &msg, BridgeMessage *queue, bool fromMsgThread) { - assert((reinterpret_cast<intptr_t>(&writeOffset) & 3) == 0); // InterlockedExchangeAdd operand should be aligned to 32 bits - uint32_t offset = InterlockedExchangeAdd(&writeOffset, 1) % MsgQueue::queueSize; - assert(msg.header.status == MsgHeader::empty); - assert(queue[offset].header.status == MsgHeader::empty); - memcpy(queue + offset, &msg, std::min(sizeof(BridgeMessage), size_t(msg.header.size))); - - queue[offset].header.signalID = fromMsgThread ? uint32_t(-1) : offset; // Don't send signal to ourselves - - assert((reinterpret_cast<intptr_t>(&queue[offset].header.status) & 3) == 0); // InterlockedExchange operand should be aligned to 32 bits - InterlockedExchange(&queue[offset].header.status, MsgHeader::sent); - - return queue + offset; + + // Find a suitable slot to post the message into + BridgeMessage *targetMsg = queue; + for(size_t i = 0; i < MsgQueue::queueSize; i++, targetMsg++) + { + assert((reinterpret_cast<intptr_t>(&targetMsg->header.status) & 3) == 0); // InterlockedExchangeAdd operand should be aligned to 32 bits + if(InterlockedCompareExchange(&targetMsg->header.status, MsgHeader::prepared, MsgHeader::empty) == MsgHeader::empty) + { + memcpy(targetMsg, &msg, std::min(sizeof(BridgeMessage), size_t(msg.header.size))); + InterlockedExchange(&targetMsg->header.signalID, fromMsgThread ? uint32_t(-1) : i); // Don't send signal to ourselves + InterlockedExchange(&targetMsg->header.status, MsgHeader::sent); + return targetMsg; + } + } + assert(false); + return nullptr; } }; Modified: trunk/OpenMPT/pluginBridge/BridgeWrapper.cpp =================================================================== --- trunk/OpenMPT/pluginBridge/BridgeWrapper.cpp 2014-03-16 23:25:31 UTC (rev 3892) +++ trunk/OpenMPT/pluginBridge/BridgeWrapper.cpp 2014-03-17 02:56:32 UTC (rev 3893) @@ -9,6 +9,8 @@ #include "stdafx.h" + +#ifndef NO_VST #include "BridgeWrapper.h" #include "misc_util.h" #include "../mptrack/Mptrack.h" @@ -186,22 +188,6 @@ sharedMem.queueMem.Close(); delete this; return false; - /* { - sharedMem.messagePipe.WaitForClient(); - //sharedMem.messagePipe.Write(&BridgeProtocolVersion, sizeof(BridgeProtocolVersion)); - - sharedMem.otherProcess = processInfo.hProcess; - const HANDLE objects[] = { sharedMem.sigToHost.ack, sharedMem.otherProcess }; - DWORD result = WaitForMultipleObjects(CountOf(objects), objects, FALSE, 10000); - if(result == WAIT_OBJECT_0) - { - success = true; - } else if(result == WAIT_OBJECT_0 + 1) - { - // Process died - } - CloseHandle(processInfo.hThread); - }*/ } @@ -723,11 +709,22 @@ { if(!sharedMem.processMem.Good()) { + ASSERT(false); return; } - new (sharedMem.processMem.view) ProcessMsg(type, numInputs, numOutputs, sampleFrames); - buf_t *ptr = reinterpret_cast<buf_t *>(static_cast<ProcessMsg *>(sharedMem.processMem.view) + 1); + ProcessMsg *msg = static_cast<ProcessMsg *>(sharedMem.processMem.view); + const VstInt32 timeInfoFlags = msg->timeInfo.flags; + new (msg) ProcessMsg(type, numInputs, numOutputs, sampleFrames); + + // Plugin asked for time info in the past (flags are set), so we anticipate that it will do that again + // and cache the time info so that plugin doesn't have to ask for it. + if(timeInfoFlags != 0) + { + msg->timeInfo = *reinterpret_cast<VstTimeInfo *>(CVstPluginManager::MasterCallBack(sharedMem.effectPtr, audioMasterGetTime, 0, timeInfoFlags, nullptr, 0.0f)); + } + + buf_t *ptr = reinterpret_cast<buf_t *>(msg + 1); for(VstInt32 i = 0; i < numInputs; i++) { memcpy(ptr, inputs[i], sampleFrames * sizeof(buf_t)); @@ -746,4 +743,6 @@ outputs[i] = ptr; // Exactly what you don't want plugins to do usually (bend your output pointers)... muahahaha! ptr += sampleFrames; } -} \ No newline at end of file +} + +#endif //NO_VST Modified: trunk/OpenMPT/plugins/MidiInOut/MidiInOut.vcxproj.filters =================================================================== --- trunk/OpenMPT/plugins/MidiInOut/MidiInOut.vcxproj.filters 2014-03-16 23:25:31 UTC (rev 3892) +++ trunk/OpenMPT/plugins/MidiInOut/MidiInOut.vcxproj.filters 2014-03-17 02:56:32 UTC (rev 3893) @@ -11,6 +11,9 @@ <Filter Include="Interfaces"> <UniqueIdentifier>{b0c52021-7533-4599-b23f-605c5676b73f}</UniqueIdentifier> </Filter> + <Filter Include="Source Files\GUI"> + <UniqueIdentifier>{877d7a3d-a6b8-451f-807d-4af1699dc061}</UniqueIdentifier> + </Filter> </ItemGroup> <ItemGroup> <ClCompile Include="MidiInOut.cpp"> @@ -30,12 +33,6 @@ </ClCompile> </ItemGroup> <ItemGroup> - <ClInclude Include="..\common\ComboBox.h"> - <Filter>Source Files</Filter> - </ClInclude> - <ClInclude Include="..\common\Label.h"> - <Filter>Source Files</Filter> - </ClInclude> <ClInclude Include="MidiInOut.h"> <Filter>Source Files</Filter> </ClInclude> @@ -60,14 +57,20 @@ <ClInclude Include="..\..\include\vstsdk2.4\public.sdk\source\vst2.x\audioeffectx.h"> <Filter>Source Files\vst2.x</Filter> </ClInclude> + <ClInclude Include="..\common\CheckBox.h"> + <Filter>Source Files\GUI</Filter> + </ClInclude> + <ClInclude Include="..\common\Label.h"> + <Filter>Source Files\GUI</Filter> + </ClInclude> + <ClInclude Include="..\common\ComboBox.h"> + <Filter>Source Files\GUI</Filter> + </ClInclude> <ClInclude Include="..\common\Window.h"> - <Filter>Source Files</Filter> + <Filter>Source Files\GUI</Filter> </ClInclude> - <ClInclude Include="..\common\CheckBox.h"> - <Filter>Source Files</Filter> - </ClInclude> <ClInclude Include="..\common\WindowBase.h"> - <Filter>Source Files</Filter> + <Filter>Source Files\GUI</Filter> </ClInclude> </ItemGroup> </Project> \ No newline at end of file Modified: trunk/OpenMPT/plugins/MidiInOut/MidiInOutEditor.cpp =================================================================== --- trunk/OpenMPT/plugins/MidiInOut/MidiInOutEditor.cpp 2014-03-16 23:25:31 UTC (rev 3892) +++ trunk/OpenMPT/plugins/MidiInOut/MidiInOutEditor.cpp 2014-03-17 02:56:32 UTC (rev 3893) @@ -38,7 +38,7 @@ //----------------------------------- { AEffEditor::open(ptr); - InitializeWindow(ptr); + Create(ptr); HWND parent = static_cast<HWND>(ptr); @@ -68,7 +68,7 @@ outputLabel.Destroy(); outputCombo.Destroy(); - DestroyWindow(); + Destroy(); AEffEditor::close(); } @@ -174,6 +174,16 @@ } break; + case CBN_DROPDOWN: + if(hwnd == inputCombo.GetHwnd() || hwnd == outputCombo.GetHwnd()) + { + // Combo box is about to drop down -> dynamically size the dropdown list + bool isInputBox = hwnd == inputCombo.GetHwnd(); + ComboBox &combo = isInputBox ? inputCombo : outputCombo; + combo.SizeDropdownList(); + } + break; + case BN_CLICKED: if(hwnd == latencyCheck.GetHwnd()) { Modified: trunk/OpenMPT/plugins/common/CheckBox.h =================================================================== --- trunk/OpenMPT/plugins/common/CheckBox.h 2014-03-16 23:25:31 UTC (rev 3892) +++ trunk/OpenMPT/plugins/common/CheckBox.h 2014-03-17 02:56:32 UTC (rev 3893) @@ -45,10 +45,7 @@ { if(hwnd != nullptr) { - SendMessage(hwnd, - BM_SETCHECK, - state ? BST_CHECKED : BST_UNCHECKED, - 0); + Button_SetCheck(hwnd, state ? BST_CHECKED : BST_UNCHECKED); } } @@ -58,10 +55,7 @@ { if(hwnd != nullptr) { - return SendMessage(hwnd, - BM_GETCHECK, - 0, - 0) != BST_UNCHECKED; + return Button_GetCheck(hwnd) != BST_UNCHECKED; } return false; } Modified: trunk/OpenMPT/plugins/common/ComboBox.h =================================================================== --- trunk/OpenMPT/plugins/common/ComboBox.h 2014-03-16 23:25:31 UTC (rev 3892) +++ trunk/OpenMPT/plugins/common/ComboBox.h 2014-03-17 02:56:32 UTC (rev 3893) @@ -57,10 +57,7 @@ { if(hwnd != nullptr) { - SendMessage(hwnd, - CB_RESETCONTENT, - 0, - 0); + ComboBox_ResetContent(hwnd); } } @@ -70,19 +67,11 @@ { if(hwnd != nullptr) { - LRESULT result = SendMessage(hwnd, - CB_ADDSTRING, - 0, - reinterpret_cast<LPARAM>(text)); - + int result = ComboBox_AddString(hwnd, text); if(result != CB_ERR) { - SendMessage(hwnd, - CB_SETITEMDATA, - result, - reinterpret_cast<LPARAM>(data) - ); - return static_cast<int>(result); + ComboBox_SetItemData(hwnd, result, data); + return result; } } return -1; @@ -94,10 +83,7 @@ { if(hwnd != nullptr) { - return static_cast<int>(SendMessage(hwnd, - CB_GETCOUNT, - 0, - 0)); + return ComboBox_GetCount(hwnd); } return 0; } @@ -108,10 +94,7 @@ { if(hwnd != nullptr) { - SendMessage(hwnd, - CB_SETCURSEL, - index, - 0); + ComboBox_SetCurSel(hwnd, index); } } @@ -121,10 +104,7 @@ { if(hwnd != nullptr) { - return SendMessage(hwnd, - CB_GETCURSEL, - 0, - 0); + return ComboBox_GetCurSel(hwnd); } return -1; } @@ -142,12 +122,34 @@ { if(hwnd != nullptr) { - return reinterpret_cast<void *>(SendMessage(hwnd, - CB_GETITEMDATA, - index, - 0)); + return reinterpret_cast<void *>(ComboBox_GetItemData(hwnd, index)); } return 0; } + // Dynamically resize the dropdown list to cover as many items as possible. + void SizeDropdownList() + { + int itemHeight = ComboBox_GetItemHeight(hwnd); + int numItems = GetCount(); + if(numItems < 2) numItems = 2; + + RECT rect; + GetWindowRect(hwnd, &rect); + + SIZE sz; + sz.cx = rect.right - rect.left; + sz.cy = itemHeight * (numItems + 2); + + if(rect.top - sz.cy < 0 || rect.bottom + sz.cy > GetSystemMetrics(SM_CYSCREEN)) + { + // Dropdown exceeds screen height - clamp it. + int k = (GetSystemMetrics(SM_CYSCREEN) - rect.bottom) / itemHeight; + if(k < rect.top / itemHeight) k = rect.top / itemHeight; + if(itemHeight * k < sz.cy) sz.cy = itemHeight * k; + } + + SetWindowPos(hwnd, NULL, 0, 0, sz.cx, sz.cy, SWP_NOMOVE | SWP_NOZORDER); + } + }; Modified: trunk/OpenMPT/plugins/common/Label.h =================================================================== --- trunk/OpenMPT/plugins/common/Label.h 2014-03-16 23:25:31 UTC (rev 3892) +++ trunk/OpenMPT/plugins/common/Label.h 2014-03-17 02:56:32 UTC (rev 3893) @@ -38,15 +38,4 @@ SendMessage(hwnd, WM_SETFONT, reinterpret_cast<WPARAM>(GetStockObject(DEFAULT_GUI_FONT)), TRUE); } - - - // Destroy the combo box. - void Destroy() - { - if(hwnd != nullptr) - { - DestroyWindow(hwnd); - } - hwnd = nullptr; - } -}; +}; Modified: trunk/OpenMPT/plugins/common/Window.h =================================================================== --- trunk/OpenMPT/plugins/common/Window.h 2014-03-16 23:25:31 UTC (rev 3892) +++ trunk/OpenMPT/plugins/common/Window.h 2014-03-17 02:56:32 UTC (rev 3893) @@ -24,9 +24,9 @@ Window() : originalWinProc(nullptr) { }; // Register window callback function and initialize window - void InitializeWindow(void *windowHandle) + void Create(void *windowHandle) { - DestroyWindow(); + Destroy(); hwnd = static_cast<HWND>(windowHandle); @@ -41,8 +41,8 @@ } - // Destroy the combo box. - void DestroyWindow() + // Destroy the window. + void Destroy() { // Restore original window processing function. if(hwnd != nullptr) Modified: trunk/OpenMPT/plugins/common/WindowBase.h =================================================================== --- trunk/OpenMPT/plugins/common/WindowBase.h 2014-03-16 23:25:31 UTC (rev 3892) +++ trunk/OpenMPT/plugins/common/WindowBase.h 2014-03-17 02:56:32 UTC (rev 3893) @@ -14,6 +14,7 @@ #define VC_EXTRALEAN #define NOMINMAX #include <windows.h> +#include <WindowsX.h> #include <tchar.h> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |