Loading...
Searching...
No Matches
Plugin.hpp
1#pragma once
2
3#define RELEASE 1
4#include <ossia/detail/flat_map.hpp>
5
6#include <QString>
7
8#include <pluginterfaces/base/funknown.h>
9#include <pluginterfaces/gui/iplugview.h>
10#include <pluginterfaces/vst/ivstaudioprocessor.h>
11#include <pluginterfaces/vst/ivstcomponent.h>
12#include <pluginterfaces/vst/ivstmessage.h>
13#include <pluginterfaces/vst/ivstunits.h>
14
15#include <string_view>
16
17#include <public.sdk/source/vst/hosting/hostclasses.h>
18#include <public.sdk/source/vst/hosting/module.h>
19#include <public.sdk/source/vst/hosting/plugprovider.h>
20
21namespace vst3
22{
23class ApplicationPlugin;
24class Model;
25
26inline QString fromString(const Steinberg::Vst::String128& str)
27{
28#if defined(_WIN32)
29 return [] <typename T>(const T& str) {
30 using char_type = std::decay_t<decltype(str[0])>;
31 if constexpr(std::is_same_v<char_type, char16_t>)
32 return QString::fromUtf16(str);
33 else
34 return QString::fromWCharArray(str);
35 }(str);
36#else
37 return QString::fromUtf16(str);
38#endif
39}
40
41// Keyed by (event bus, MIDI channel 0-15, controller number). The channel is
42// part of the key because VST3 lets a plug-in assign a different parameter per
43// channel, which is how an MPE-aware plug-in exposes per-voice pitch bend -
44// and MPE senders put every note on its own member channel, never channel 0.
45using MIDIControls
46 = ossia::flat_map<std::tuple<int, int, int>, Steinberg::Vst::ParamID>;
47class PlugFrame;
48class ComponentHandler;
49struct Plugin
50{
51 Plugin() = default;
52 Plugin(const Plugin&) = default;
53 Plugin(Plugin&&) = default;
54 Plugin& operator=(const Plugin&) = default;
55 Plugin& operator=(Plugin&&) = default;
56
57 ~Plugin();
58
59 void load(
60 Model& model, ApplicationPlugin& ctx, const std::string& path,
61 const VST3::UID& uid, double sr, int max_bs);
62 operator bool() const noexcept { return component && processor; }
63
64 std::string path;
65 VST3::Hosting::Module::Ptr mdl;
66 Steinberg::Vst::IComponent* component{};
67 Steinberg::Vst::IAudioProcessor* processor{};
68 Steinberg::Vst::IEditController* controller{};
69 Steinberg::Vst::IUnitInfo* units{};
70 Steinberg::IPlugView* view{};
71 PlugFrame* plugFrame{};
72
73 // Connection points of the component and the controller, kept around because
74 // VST3 mandates disconnecting them before terminating the plug-in
75 Steinberg::Vst::IConnectionPoint* componentCP{};
76 Steinberg::Vst::IConnectionPoint* controllerCP{};
77
78 // Given to the controller: it points to the Model, so it has to be unset
79 // before the Model dies
80 ComponentHandler* componentHandler{};
81
82 void loadAudioProcessor(ApplicationPlugin& ctx);
83 void loadEditController(Model& model, ApplicationPlugin& ctx);
84 void loadView(Model& model);
85 void loadBuses();
86 void loadPresets();
87
88 void loadProcessorStateToController();
89
90 void start(double sample_rate, int max_bs);
91 void stop();
92
93 bool supports_double{};
94 bool ui_available{};
95 bool ui_owned{};
96
97 // initialize() succeeded and must be paired with exactly one terminate()
98 bool component_initialized{};
99 bool controller_initialized{};
100
101 // Single-component effect: the component *is* the edit controller, thus it
102 // must only be initialized and terminated once
103 bool controller_is_component{};
104 int audio_ins = 0;
105 int event_ins = 0;
106 int audio_outs = 0;
107 int event_outs = 0;
108
109 MIDIControls midiControls{};
110
111 Steinberg::Vst::ProgramListInfo programs;
112};
113
114#if __cpp_concepts >= 201907
115template <typename T>
116concept BusVisitor = requires(T&& vis)
117{
118 vis.audioIn(Steinberg::Vst::BusInfo{}, int{});
119 vis.audioOut(Steinberg::Vst::BusInfo{}, int{});
120 vis.eventIn(Steinberg::Vst::BusInfo{}, int{});
121 vis.eventOut(Steinberg::Vst::BusInfo{}, int{});
122};
123void forEachBus(BusVisitor auto&& visitor, Steinberg::Vst::IComponent& component)
124#else
125template <typename T>
126void forEachBus(T&& visitor, Steinberg::Vst::IComponent& component)
127#endif
128{
129 const int audio_ins
130 = component.getBusCount(Steinberg::Vst::kAudio, Steinberg::Vst::kInput);
131 const int event_ins
132 = component.getBusCount(Steinberg::Vst::kEvent, Steinberg::Vst::kInput);
133 const int audio_outs
134 = component.getBusCount(Steinberg::Vst::kAudio, Steinberg::Vst::kOutput);
135 const int event_outs
136 = component.getBusCount(Steinberg::Vst::kEvent, Steinberg::Vst::kOutput);
137
138 Steinberg::Vst::BusInfo bus;
139 for(int i = 0; i < audio_ins; i++)
140 {
141 component.getBusInfo(Steinberg::Vst::kAudio, Steinberg::Vst::kInput, i, bus);
142 visitor.audioIn(bus, i);
143 }
144
145 for(int i = 0; i < event_ins; i++)
146 {
147 component.getBusInfo(Steinberg::Vst::kEvent, Steinberg::Vst::kInput, i, bus);
148 visitor.eventIn(bus, i);
149 }
150
151 for(int i = 0; i < audio_outs; i++)
152 {
153 component.getBusInfo(Steinberg::Vst::kAudio, Steinberg::Vst::kOutput, i, bus);
154 visitor.audioOut(bus, i);
155 }
156
157 for(int i = 0; i < event_outs; i++)
158 {
159 component.getBusInfo(Steinberg::Vst::kEvent, Steinberg::Vst::kOutput, i, bus);
160 visitor.eventOut(bus, i);
161 }
162}
163}
Definition score-plugin-vst3/Vst3/ApplicationPlugin.hpp:100
Definition EditHandler.hpp:17
Definition score-plugin-vst3/Vst3/EffectModel.hpp:43
Definition PlugFrame.hpp:14
Definition Plugin.hpp:50