aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/pluginBridge/AEffectWrapper.h
diff options
context:
space:
mode:
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/pluginBridge/AEffectWrapper.h')
-rw-r--r--Src/external_dependencies/openmpt-trunk/pluginBridge/AEffectWrapper.h274
1 files changed, 274 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/pluginBridge/AEffectWrapper.h b/Src/external_dependencies/openmpt-trunk/pluginBridge/AEffectWrapper.h
new file mode 100644
index 00000000..93c64db0
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/pluginBridge/AEffectWrapper.h
@@ -0,0 +1,274 @@
+/*
+ * AEffectWrapper.h
+ * ----------------
+ * Purpose: Helper functions and structs for translating the VST AEffect struct between bit boundaries.
+ * Notes : (currently none)
+ * Authors: Johannes Schultz (OpenMPT Devs)
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#pragma once
+
+#include "openmpt/all/BuildSettings.hpp"
+
+#include <vector>
+#include "../mptrack/plugins/VstDefinitions.h"
+
+OPENMPT_NAMESPACE_BEGIN
+
+#pragma pack(push, 8)
+
+template <typename ptr_t>
+struct AEffectProto
+{
+ int32 magic;
+ ptr_t dispatcher;
+ ptr_t process;
+ ptr_t setParameter;
+ ptr_t getParameter;
+
+ int32 numPrograms;
+ uint32 numParams;
+ int32 numInputs;
+ int32 numOutputs;
+
+ int32 flags;
+
+ ptr_t resvd1;
+ ptr_t resvd2;
+
+ int32 initialDelay;
+
+ int32 realQualities;
+ int32 offQualities;
+ float ioRatio;
+
+ ptr_t object;
+ ptr_t user;
+
+ int32 uniqueID;
+ int32 version;
+
+ ptr_t processReplacing;
+ ptr_t processDoubleReplacing;
+ char future[56];
+
+ // Convert native representation to bridge representation.
+ // Don't overwrite any values managed by the bridge wrapper or host in general.
+ void FromNative(const Vst::AEffect &in)
+ {
+ magic = in.magic;
+
+ numPrograms = in.numPrograms;
+ numParams = in.numParams;
+ numInputs = in.numInputs;
+ numOutputs = in.numOutputs;
+
+ flags = in.flags;
+
+ initialDelay = in.initialDelay;
+
+ realQualities = in.realQualities;
+ offQualities = in.offQualities;
+ ioRatio = in.ioRatio;
+
+ uniqueID = in.uniqueID;
+ version = in.version;
+
+ if(in.processReplacing == nullptr)
+ flags &= ~Vst::effFlagsCanReplacing;
+ if(in.processDoubleReplacing == nullptr)
+ flags &= ~Vst::effFlagsCanDoubleReplacing;
+ }
+};
+
+using AEffect32 = AEffectProto<int32>;
+using AEffect64 = AEffectProto<int64>;
+
+#pragma pack(pop)
+
+
+// Translate a VSTEvents struct to bridge format (placed in data vector)
+static void TranslateVstEventsToBridge(std::vector<char> &outData, const Vst::VstEvents &events, int32 targetPtrSize)
+{
+ outData.reserve(outData.size() + sizeof(int32) + sizeof(Vst::VstMidiEvent) * events.numEvents);
+ // Write number of events
+ PushToVector(outData, events.numEvents);
+ // Write events
+ for(const auto event : events)
+ {
+ if(event->type == Vst::kVstSysExType)
+ {
+ // This is going to be messy since the VstMidiSysexEvent event has a different size than other events on 64-bit platforms.
+ // We are going to write the event using the target process pointer size.
+ auto sysExEvent = *static_cast<const Vst::VstMidiSysexEvent *>(event);
+ sysExEvent.byteSize = 4 * sizeof(int32) + 4 * targetPtrSize; // It's 5 int32s and 3 pointers but that means that on 64-bit platforms, the fifth int32 is padded for alignment.
+ PushToVector(outData, sysExEvent, 5 * sizeof(int32)); // Exclude the three pointers at the end for now
+ if(targetPtrSize > static_cast<int32>(sizeof(int32))) // Padding for 64-bit required?
+ outData.insert(outData.end(), targetPtrSize - sizeof(int32), 0);
+ outData.insert(outData.end(), 3 * targetPtrSize, 0); // Make space for pointer + two reserved intptr_ts
+ // Embed SysEx dump as well...
+ auto sysex = reinterpret_cast<const char *>(sysExEvent.sysexDump);
+ outData.insert(outData.end(), sysex, sysex + sysExEvent.dumpBytes);
+ } else if(event->type == Vst::kVstMidiType)
+ {
+ // randomid by Insert Piz Here sends events of type kVstMidiType, but with a claimed size of 24 bytes instead of 32.
+ Vst::VstMidiEvent midiEvent;
+ std::memcpy(&midiEvent, event, sizeof(midiEvent));
+ midiEvent.byteSize = sizeof(midiEvent);
+ PushToVector(outData, midiEvent, sizeof(midiEvent));
+ } else
+ {
+ PushToVector(outData, *event, event->byteSize);
+ }
+ }
+}
+
+
+// Translate bridge format (void *ptr) back to VSTEvents struct (placed in data vector)
+static void TranslateBridgeToVstEvents(std::vector<char> &outData, const void *inData)
+{
+ const int32 numEvents = *static_cast<const int32 *>(inData);
+
+ // First element is really a int32, but in case of 64-bit builds, the next field gets aligned anyway.
+ const size_t headerSize = sizeof(intptr_t) + sizeof(intptr_t) + sizeof(Vst::VstEvent *) * numEvents;
+ outData.reserve(headerSize + sizeof(Vst::VstMidiEvent) * numEvents);
+ outData.resize(headerSize, 0);
+ if(numEvents == 0)
+ return;
+
+ // Copy over event data (this is required for dumb SynthEdit plugins that don't copy over the event data during effProcessEvents)
+ const char *readOffset = static_cast<const char *>(inData) + sizeof(int32);
+ for(int32 i = 0; i < numEvents; i++)
+ {
+ auto *event = reinterpret_cast<const Vst::VstEvent *>(readOffset);
+ outData.insert(outData.end(), readOffset, readOffset + event->byteSize);
+ readOffset += event->byteSize;
+
+ if(event->type == Vst::kVstSysExType)
+ {
+ // Copy over sysex dump
+ auto *sysExEvent = static_cast<const Vst::VstMidiSysexEvent *>(event);
+ outData.insert(outData.end(), readOffset, readOffset + sysExEvent->dumpBytes);
+ readOffset += sysExEvent->dumpBytes;
+ }
+ }
+
+ // Write pointers
+ auto events = reinterpret_cast<Vst::VstEvents *>(outData.data());
+ events->numEvents = numEvents;
+ char *offset = outData.data() + headerSize;
+ for(int32 i = 0; i < numEvents; i++)
+ {
+ events->events[i] = reinterpret_cast<Vst::VstEvent *>(offset);
+ offset += events->events[i]->byteSize;
+ if(events->events[i]->type == Vst::kVstSysExType)
+ {
+ auto sysExEvent = static_cast<Vst::VstMidiSysexEvent *>(events->events[i]);
+ sysExEvent->sysexDump = reinterpret_cast<const std::byte *>(offset);
+ offset += sysExEvent->dumpBytes;
+ }
+ }
+}
+
+
+// Calculate the size total of the VSTEvents (without header) in bridge format
+static size_t BridgeVstEventsSize(const void *ptr)
+{
+ const int32 numEvents = *static_cast<const int32 *>(ptr);
+ size_t size = 0;
+ for(int32 i = 0; i < numEvents; i++)
+ {
+ const auto event = reinterpret_cast<const Vst::VstEvent *>(static_cast<const char *>(ptr) + sizeof(int32) + size);
+ size += event->byteSize;
+ if(event->type == Vst::kVstSysExType)
+ {
+ size += static_cast<const Vst::VstMidiSysexEvent *>(event)->dumpBytes;
+ }
+ }
+ return size;
+}
+
+
+static void TranslateVstFileSelectToBridge(std::vector<char> &outData, const Vst::VstFileSelect &fileSelect, int32 targetPtrSize)
+{
+ outData.reserve(outData.size() + sizeof(Vst::VstFileSelect) + fileSelect.numFileTypes * sizeof(Vst::VstFileType));
+ PushToVector(outData, fileSelect.command);
+ PushToVector(outData, fileSelect.type);
+ PushToVector(outData, fileSelect.macCreator);
+ PushToVector(outData, fileSelect.numFileTypes);
+ outData.insert(outData.end(), targetPtrSize, 0); // fileTypes
+ PushToVector(outData, fileSelect.title);
+ outData.insert(outData.end(), 2 * targetPtrSize, 0); // initialPath, returnPath
+ PushToVector(outData, fileSelect.sizeReturnPath);
+ if(targetPtrSize > static_cast<int32>(sizeof(int32)))
+ outData.insert(outData.end(), targetPtrSize - sizeof(int32), 0); // padding
+ outData.insert(outData.end(), targetPtrSize, 0); // returnMultiplePaths
+ PushToVector(outData, fileSelect.numReturnPaths);
+ outData.insert(outData.end(), targetPtrSize, 0); // reserved
+ PushToVector(outData, fileSelect.reserved2);
+
+ if(fileSelect.command != Vst::kVstDirectorySelect)
+ {
+ for(int32 i = 0; i < fileSelect.numFileTypes; i++)
+ {
+ PushToVector(outData, fileSelect.fileTypes[i]);
+ }
+ }
+
+ if(fileSelect.command == Vst::kVstMultipleFilesLoad)
+ {
+ outData.insert(outData.end(), fileSelect.numReturnPaths * targetPtrSize, 0);
+ for(int32 i = 0; i < fileSelect.numReturnPaths; i++)
+ {
+ PushZStringToVector(outData, fileSelect.returnMultiplePaths[i]);
+ }
+ }
+
+ PushZStringToVector(outData, fileSelect.initialPath);
+ PushZStringToVector(outData, fileSelect.returnPath);
+}
+
+
+static void TranslateBridgeToVstFileSelect(std::vector<char> &outData, const void *inData, size_t srcSize)
+{
+ outData.assign(static_cast<const char *>(inData), static_cast<const char *>(inData) + srcSize);
+
+ // Fixup pointers
+ Vst::VstFileSelect &fileSelect = *reinterpret_cast<Vst::VstFileSelect *>(outData.data());
+ auto ptrOffset = outData.data() + sizeof(Vst::VstFileSelect);
+
+ if(fileSelect.command != Vst::kVstDirectorySelect)
+ {
+ fileSelect.fileTypes = reinterpret_cast<Vst::VstFileType *>(ptrOffset);
+ ptrOffset += fileSelect.numFileTypes * sizeof(Vst::VstFileType);
+ } else
+ {
+ fileSelect.fileTypes = nullptr;
+ }
+
+ if(fileSelect.command == Vst::kVstMultipleFilesLoad)
+ {
+ fileSelect.returnMultiplePaths = reinterpret_cast<char **>(ptrOffset);
+ ptrOffset += fileSelect.numReturnPaths * sizeof(char *);
+
+ for(int32 i = 0; i < fileSelect.numReturnPaths; i++)
+ {
+ fileSelect.returnMultiplePaths[i] = ptrOffset;
+ ptrOffset += strlen(fileSelect.returnMultiplePaths[i]) + 1;
+ }
+ } else
+ {
+ fileSelect.returnMultiplePaths = nullptr;
+ }
+
+ fileSelect.initialPath = ptrOffset;
+ ptrOffset += strlen(fileSelect.initialPath) + 1;
+ fileSelect.returnPath = ptrOffset;
+ fileSelect.sizeReturnPath = static_cast<int32>(srcSize - std::distance(outData.data(), ptrOffset));
+ ptrOffset += strlen(fileSelect.returnPath) + 1;
+}
+
+
+OPENMPT_NAMESPACE_END