VstEventQueue.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. /*
  2. * VstEventQueue.h
  3. * ---------------
  4. * Purpose: Event queue for VST events.
  5. * Notes : Modelled after an idea from https://www.kvraudio.com/forum/viewtopic.php?p=3043807#p3043807
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #pragma once
  10. #include "openmpt/all/BuildSettings.hpp"
  11. #include <deque>
  12. #include "mpt/mutex/mutex.hpp"
  13. #include "VstDefinitions.h"
  14. OPENMPT_NAMESPACE_BEGIN
  15. class VstEventQueue : public Vst::VstEvents
  16. {
  17. protected:
  18. // Although originally all event types were apparently supposed to be of the same size, this is not the case on 64-Bit systems.
  19. // VstMidiSysexEvent contains 3 pointers, so the struct size differs between 32-Bit and 64-Bit systems.
  20. union Event
  21. {
  22. Vst::VstEvent event;
  23. Vst::VstMidiEvent midi;
  24. Vst::VstMidiSysexEvent sysex;
  25. };
  26. // Here we store our events which are then inserted into the fixed-size event buffer sent to the plugin.
  27. std::deque<Event> eventQueue;
  28. // Since plugins can also add events to the queue (even from a different thread than the processing thread),
  29. // we need to ensure that reading and writing is never done in parallel.
  30. mpt::mutex criticalSection;
  31. public:
  32. VstEventQueue()
  33. {
  34. numEvents = 0;
  35. reserved = 0;
  36. std::fill(std::begin(events), std::end(events), nullptr);
  37. }
  38. // Get the number of events that are currently queued, but not in the output buffer.
  39. size_t GetNumQueuedEvents()
  40. {
  41. return eventQueue.size() - numEvents;
  42. }
  43. // Add a VST event to the queue. Returns true on success.
  44. // Set insertFront to true to prioritise this event (i.e. add it at the front of the queue instead of the back)
  45. bool Enqueue(const Vst::VstEvent *event, bool insertFront = false)
  46. {
  47. MPT_ASSERT(event->type != Vst::kVstSysExType || event->byteSize == sizeof(Vst::VstMidiSysexEvent));
  48. MPT_ASSERT(event->type != Vst::kVstMidiType || event->byteSize == sizeof(Vst::VstMidiEvent));
  49. Event copyEvent;
  50. size_t copySize;
  51. // randomid by Insert Piz Here sends events of type kVstMidiType, but with a claimed size of 24 bytes instead of 32.
  52. // Hence, we enforce the size of known events.
  53. if(event->type == Vst::kVstSysExType)
  54. copySize = sizeof(Vst::VstMidiSysexEvent);
  55. else if(event->type == Vst::kVstMidiType)
  56. copySize = sizeof(Vst::VstMidiEvent);
  57. else
  58. copySize = std::min(size_t(event->byteSize), sizeof(copyEvent));
  59. memcpy(&copyEvent, event, copySize);
  60. if(event->type == Vst::kVstSysExType)
  61. {
  62. // SysEx messages need to be copied, as the space used for the dump might be freed in the meantime.
  63. auto &e = copyEvent.sysex;
  64. auto sysexDump = new (std::nothrow) std::byte[e.dumpBytes];
  65. if(sysexDump == nullptr)
  66. return false;
  67. memcpy(sysexDump, e.sysexDump, e.dumpBytes);
  68. e.sysexDump = sysexDump;
  69. }
  70. mpt::lock_guard<mpt::mutex> lock(criticalSection);
  71. if(insertFront)
  72. eventQueue.push_front(copyEvent);
  73. else
  74. eventQueue.push_back(copyEvent);
  75. return true;
  76. }
  77. // Set up the queue for transmitting to the plugin. Returns number of elements that are going to be transmitted.
  78. int32 Finalise()
  79. {
  80. mpt::lock_guard<mpt::mutex> lock(criticalSection);
  81. numEvents = static_cast<int32>(std::min(eventQueue.size(), MAX_EVENTS));
  82. for(int32 i = 0; i < numEvents; i++)
  83. {
  84. events[i] = &eventQueue[i].event;
  85. }
  86. return numEvents;
  87. }
  88. // Remove transmitted events from the queue
  89. void Clear()
  90. {
  91. mpt::lock_guard<mpt::mutex> lock(criticalSection);
  92. if(numEvents)
  93. {
  94. // Release temporarily allocated buffer for SysEx messages
  95. for(auto e = eventQueue.begin(); e != eventQueue.begin() + numEvents; ++e)
  96. {
  97. if(e->event.type == Vst::kVstSysExType)
  98. {
  99. delete[] e->sysex.sysexDump;
  100. }
  101. }
  102. eventQueue.erase(eventQueue.begin(), eventQueue.begin() + numEvents);
  103. numEvents = 0;
  104. }
  105. }
  106. };
  107. OPENMPT_NAMESPACE_END