winamp/Src/external_dependencies/openmpt-trunk/pluginBridge/AEffectWrapper.h
2024-09-24 14:54:57 +02:00

275 lines
8.8 KiB
C++

/*
* 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