// yabridge: a Wine plugin bridge
// Copyright (C) 2020-2024 Robbert van der Helm
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
#include "vst2.h"
AEffect& update_aeffect(AEffect& plugin,
const AEffect& updated_plugin) noexcept {
plugin.magic = updated_plugin.magic;
plugin.numPrograms = updated_plugin.numPrograms;
plugin.numParams = updated_plugin.numParams;
plugin.numInputs = updated_plugin.numInputs;
plugin.numOutputs = updated_plugin.numOutputs;
plugin.flags = updated_plugin.flags;
plugin.initialDelay = updated_plugin.initialDelay;
plugin.empty3a = updated_plugin.empty3a;
plugin.empty3b = updated_plugin.empty3b;
plugin.unkown_float = updated_plugin.unkown_float;
plugin.uniqueID = updated_plugin.uniqueID;
plugin.version = updated_plugin.version;
return plugin;
}
DynamicVstEvents::DynamicVstEvents() noexcept {}
DynamicVstEvents::DynamicVstEvents(const VstEvents& c_events)
: events_(c_events.numEvents) {
// Copy from the C-style array into a vector for serialization
for (int i = 0; i < c_events.numEvents; i++) {
events_[i] = *c_events.events[i];
// If we encounter a SysEx event, also store the payload data in an
// associative list (so we can potentially still avoid allocations)
const auto sysex_event =
reinterpret_cast(c_events.events[i]);
if (sysex_event->type == kVstSysExType) {
sysex_data_.emplace_back(
i, std::string(sysex_event->sysexDump, sysex_event->byteSize));
}
}
}
VstEvents& DynamicVstEvents::as_c_events() {
// As explained in `vst_events_buffer`'s docstring we have to build the
// `VstEvents` struct by hand on the heap since it's actually a dynamically
// sized object. If we encountered any SysEx events, then we'll need to
// update the pointers in `events` to point to the correct data location.
for (const auto& [event_idx, data] : sysex_data_) {
auto& sysex_event =
reinterpret_cast(events_[event_idx]);
sysex_event.sysexDump = const_cast(data.data());
}
// First we need to allocate enough memory for the entire object. The events
// are stored as pointers to objects in the `events` vector that we sent
// over the socket. Our definition of `VstEvents` contains a single
// `VstEvent`, so our buffer needs to be large enough to store that plus the
// number of events minus one pointers.
static_assert(std::extent_v == 1);
const size_t buffer_size =
sizeof(VstEvents) +
((events_.size() - 1) *
sizeof(VstEvent*)); // NOLINT(bugprone-sizeof-expression)
vst_events_buffer_.resize(buffer_size);
// Now we can populate the VLA with pointers to the objects in the `events`
// vector
VstEvents* vst_events =
reinterpret_cast(vst_events_buffer_.data());
vst_events->numEvents = static_cast(events_.size());
std::transform(events_.begin(), events_.end(), vst_events->events,
[](VstEvent& event) -> VstEvent* { return &event; });
return *vst_events;
}
DynamicSpeakerArrangement::DynamicSpeakerArrangement() noexcept {}
DynamicSpeakerArrangement::DynamicSpeakerArrangement(
const VstSpeakerArrangement& speaker_arrangement)
: flags_(speaker_arrangement.flags),
speakers_(speaker_arrangement.num_speakers) {
// Copy from the C-style array into a vector for serialization
speakers_.assign(
&speaker_arrangement.speakers[0],
&speaker_arrangement.speakers[speaker_arrangement.num_speakers]);
}
VstSpeakerArrangement& DynamicSpeakerArrangement::as_c_speaker_arrangement() {
// Just like in `DynamicVstEvents::as_c_events()`, we will use our buffer
// vector to allocate enough heap space and then reconstruct the original
// `VstSpeakerArrangement` object passed to the constructor.
static_assert(std::extent_v ==
2);
const size_t buffer_size = sizeof(VstSpeakerArrangement) +
((speakers_.size() - 2) * sizeof(VstSpeaker));
speaker_arrangement_buffer_.resize(buffer_size);
// Now we'll just copy over the elements from our vector to the VLA in this
// struct
VstSpeakerArrangement* speaker_arrangement =
reinterpret_cast(
speaker_arrangement_buffer_.data());
speaker_arrangement->flags = flags_;
speaker_arrangement->num_speakers = static_cast(speakers_.size());
std::copy(speakers_.begin(), speakers_.end(),
speaker_arrangement->speakers);
return *speaker_arrangement;
}
std::vector& DynamicSpeakerArrangement::as_raw_data() {
// This will populate the buffer for us with the struct data
as_c_speaker_arrangement();
return speaker_arrangement_buffer_;
}