diff options
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/pluginBridge/AEffectWrapper.h')
-rw-r--r-- | Src/external_dependencies/openmpt-trunk/pluginBridge/AEffectWrapper.h | 274 |
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 |