diff --git a/README.md b/README.md
index 5f96bbb7..a73135eb 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,7 @@ imcomplete list of things that still have to be done before this can be used:
- Fully implemented:
- `GetPluginFactory()` and `IPluginFactory{,2,3}`
- `IPluginBase` and `IComponent`
- - `IParamValueQueue`
+ - `IParameterChanges` and `IParamValueQueue`
- Update the GitHub Actions workflows.
- Update yabridgectl to handle buth VST2 and VST3 plugins.
- Update all documentation to refer to VST2 and VST3 support separately, and
diff --git a/meson.build b/meson.build
index 79972446..d8c0fbb8 100644
--- a/meson.build
+++ b/meson.build
@@ -81,6 +81,7 @@ vst3_plugin_sources = [
'src/common/serialization/vst3/component.cpp',
'src/common/serialization/vst3/host-application.cpp',
'src/common/serialization/vst3/param-value-queue.cpp',
+ 'src/common/serialization/vst3/parameter-changes.cpp',
'src/common/serialization/vst3/plugin-factory.cpp',
'src/common/configuration.cpp',
'src/common/plugins.cpp',
@@ -117,6 +118,7 @@ if with_vst3
'src/common/serialization/vst3/component.cpp',
'src/common/serialization/vst3/host-application.cpp',
'src/common/serialization/vst3/param-value-queue.cpp',
+ 'src/common/serialization/vst3/parameter-changes.cpp',
'src/common/serialization/vst3/plugin-factory.cpp',
'src/wine-host/bridges/vst3-impls/host-application.cpp',
'src/wine-host/bridges/vst3.cpp',
diff --git a/src/common/serialization/vst3/param-value-queue.cpp b/src/common/serialization/vst3/param-value-queue.cpp
index 02f1c75f..25e93375 100644
--- a/src/common/serialization/vst3/param-value-queue.cpp
+++ b/src/common/serialization/vst3/param-value-queue.cpp
@@ -18,8 +18,12 @@
YaParamValueQueue::YaParamValueQueue(){FUNKNOWN_CTOR}
-YaParamValueQueue::YaParamValueQueue(
- Steinberg::Vst::IParamValueQueue& original_queue)
+YaParamValueQueue::YaParamValueQueue(Steinberg::Vst::ParamID parameter_id)
+ : parameter_id(parameter_id){FUNKNOWN_CTOR}
+
+ // clang-format /really/ doesn't like these macros
+ YaParamValueQueue::YaParamValueQueue(Steinberg::Vst::IParamValueQueue &
+ original_queue)
: parameter_id(original_queue.getParameterId()),
queue(original_queue.getPointCount()) {
FUNKNOWN_CTOR
diff --git a/src/common/serialization/vst3/param-value-queue.h b/src/common/serialization/vst3/param-value-queue.h
index 49e0c1de..9b3b02fe 100644
--- a/src/common/serialization/vst3/param-value-queue.h
+++ b/src/common/serialization/vst3/param-value-queue.h
@@ -36,10 +36,16 @@ class YaParamValueQueue : public Steinberg::Vst::IParamValueQueue {
*/
YaParamValueQueue();
+ /**
+ * Create an empty queue for a specific parameter. Used in
+ * `YaParameterChanges::addParameterData`.
+ */
+ YaParamValueQueue(Steinberg::Vst::ParamID parameter_id);
+
/**
* Read data from an existing `IParamValueQueue` object.
*/
- YaParamValueQueue(Steinberg::Vst::IParamValueQueue&);
+ YaParamValueQueue(Steinberg::Vst::IParamValueQueue& original_queue);
~YaParamValueQueue();
diff --git a/src/common/serialization/vst3/parameter-changes.cpp b/src/common/serialization/vst3/parameter-changes.cpp
new file mode 100644
index 00000000..0b78efee
--- /dev/null
+++ b/src/common/serialization/vst3/parameter-changes.cpp
@@ -0,0 +1,64 @@
+// yabridge: a Wine VST bridge
+// Copyright (C) 2020 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 "parameter-changes.h"
+
+YaParameterChanges::YaParameterChanges(){FUNKNOWN_CTOR}
+
+YaParameterChanges::YaParameterChanges(
+ Steinberg::Vst::IParameterChanges& original_queues) {
+ FUNKNOWN_CTOR
+
+ // Copy over all parameter changne queues. Everything gets converted to
+ // `YaParamValueQueue`s
+ queues.reserve(original_queues.getParameterCount());
+ for (int i = 0; i < original_queues.getParameterCount(); i++) {
+ queues.push_back(*original_queues.getParameterData(i));
+ }
+}
+
+YaParameterChanges::~YaParameterChanges() {
+ FUNKNOWN_DTOR
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
+IMPLEMENT_FUNKNOWN_METHODS(YaParameterChanges,
+ Steinberg::Vst::IParameterChanges,
+ Steinberg::Vst::IParameterChanges::iid)
+#pragma GCC diagnostic pop
+
+int32 PLUGIN_API YaParameterChanges::getParameterCount() {
+ return queues.size();
+}
+
+Steinberg::Vst::IParamValueQueue* PLUGIN_API
+YaParameterChanges::getParameterData(int32 index) {
+ if (index < static_cast(queues.size())) {
+ return &queues[index];
+ } else {
+ return nullptr;
+ }
+}
+
+Steinberg::Vst::IParamValueQueue* PLUGIN_API
+YaParameterChanges::addParameterData(const Steinberg::Vst::ParamID& id,
+ int32& index /*out*/) {
+ index = queues.size();
+ queues.push_back(YaParamValueQueue(id));
+
+ return &queues[index];
+}
diff --git a/src/common/serialization/vst3/parameter-changes.h b/src/common/serialization/vst3/parameter-changes.h
new file mode 100644
index 00000000..0eabaa30
--- /dev/null
+++ b/src/common/serialization/vst3/parameter-changes.h
@@ -0,0 +1,68 @@
+// yabridge: a Wine VST bridge
+// Copyright (C) 2020 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 .
+
+#pragma once
+
+#include
+
+#include "base.h"
+#include "param-value-queue.h"
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+
+/**
+ * Wraps around `IParameterChanges` for serialization purposes. Used in
+ * `YaProcessData`.
+ */
+class YaParameterChanges : public Steinberg::Vst::IParameterChanges {
+ public:
+ /**
+ * Default constructor with an empty parameter changes list. The plugin can
+ * use this to output data.
+ */
+ YaParameterChanges();
+
+ /**
+ * Read data from an existing `IParameterChanges` object.
+ */
+ YaParameterChanges(Steinberg::Vst::IParameterChanges& original_queues);
+
+ ~YaParameterChanges();
+
+ DECLARE_FUNKNOWN_METHODS
+
+ // From `IParameterChanges`
+ int32 PLUGIN_API getParameterCount() override;
+ Steinberg::Vst::IParamValueQueue* PLUGIN_API
+ getParameterData(int32 index) override;
+ Steinberg::Vst::IParamValueQueue* PLUGIN_API
+ addParameterData(const Steinberg::Vst::ParamID& id,
+ int32& index /*out*/) override;
+
+ template
+ void serialize(S& s) {
+ s.container(queues, 1 << 16);
+ }
+
+ private:
+ /**
+ * The parameter value changes queues.
+ */
+ std::vector queues;
+};
+
+#pragma GCC diagnostic pop