1 /* -----------------------------------------------------------------------------
2 *
3 * Giada - Your Hardcore Loopmachine
4 *
5 * -----------------------------------------------------------------------------
6 *
7 * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
8 *
9 * This file is part of Giada - Your Hardcore Loopmachine.
10 *
11 * Giada - Your Hardcore Loopmachine is free software: you can
12 * redistribute it and/or modify it under the terms of the GNU General
13 * Public License as published by the Free Software Foundation, either
14 * version 3 of the License, or (at your option) any later version.
15 *
16 * Giada - Your Hardcore Loopmachine is distributed in the hope that it
17 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
18 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 * See the GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Giada - Your Hardcore Loopmachine. If not, see
23 * <http://www.gnu.org/licenses/>.
24 *
25 * -------------------------------------------------------------------------- */
26
27
28 #ifdef WITH_VST
29
30 #include <cassert>
31 #include "utils/log.h"
32 #include "utils/vector.h"
33 #include "core/model/model.h"
34 #include "core/channels/channel.h"
35 #include "core/const.h"
36 #include "core/plugins/plugin.h"
37 #include "core/plugins/pluginManager.h"
38 #include "core/plugins/pluginHost.h"
39
40
41 namespace giada {
42 namespace m {
43 namespace pluginHost
44 {
45 namespace
46 {
47 juce::MessageManager* messageManager_;
48 juce::AudioBuffer<float> audioBuffer_;
49 ID pluginId_;
50
51
52 /* -------------------------------------------------------------------------- */
53
54
giadaToJuceTempBuf_(const AudioBuffer & outBuf)55 void giadaToJuceTempBuf_(const AudioBuffer& outBuf)
56 {
57 for (int i=0; i<outBuf.countFrames(); i++)
58 for (int j=0; j<outBuf.countChannels(); j++)
59 audioBuffer_.setSample(j, i, outBuf[i][j]);
60 }
61
62
63 /* juceToGiadaOutBuf_
64 Converts buffer from Juce to Giada. A note for the future: if we overwrite (=)
65 (as we do now) it's SEND, if we add (+) it's INSERT. */
66
juceToGiadaOutBuf_(AudioBuffer & outBuf)67 void juceToGiadaOutBuf_(AudioBuffer& outBuf)
68 {
69 for (int i=0; i<outBuf.countFrames(); i++)
70 for (int j=0; j<outBuf.countChannels(); j++)
71 outBuf[i][j] = audioBuffer_.getSample(j, i);
72 }
73
74
75 /* -------------------------------------------------------------------------- */
76
77
processPlugins_(const std::vector<ID> & pluginIds,juce::MidiBuffer & events)78 void processPlugins_(const std::vector<ID>& pluginIds, juce::MidiBuffer& events)
79 {
80 model::PluginsLock l(model::plugins);
81
82 for (ID id : pluginIds) {
83 Plugin& p = model::get(model::plugins, id);
84 if (!p.valid || p.isSuspended() || p.isBypassed())
85 continue;
86 p.process(audioBuffer_, events);
87 events.clear();
88 }
89 }
90
91
clonePlugin_(ID pluginId)92 ID clonePlugin_(ID pluginId)
93 {
94 model::PluginsLock l(model::plugins);
95
96 const Plugin& original = model::get(model::plugins, pluginId);
97 std::unique_ptr<Plugin> clone = pluginManager::makePlugin(original);
98 ID newId = clone->id;
99
100 model::plugins.push(std::move(clone));
101
102 return newId;
103 }
104 } // {anonymous}
105
106
107 /* -------------------------------------------------------------------------- */
108 /* -------------------------------------------------------------------------- */
109 /* -------------------------------------------------------------------------- */
110
111
close()112 void close()
113 {
114 messageManager_->deleteInstance();
115 model::plugins.clear();
116 }
117
118
119 /* -------------------------------------------------------------------------- */
120
121
init(int buffersize)122 void init(int buffersize)
123 {
124 messageManager_ = juce::MessageManager::getInstance();
125 audioBuffer_.setSize(G_MAX_IO_CHANS, buffersize);
126 pluginId_ = 0;
127 }
128
129
130 /* -------------------------------------------------------------------------- */
131
132
processStack(AudioBuffer & outBuf,const std::vector<ID> & pluginIds,juce::MidiBuffer * events)133 void processStack(AudioBuffer& outBuf, const std::vector<ID>& pluginIds,
134 juce::MidiBuffer* events)
135 {
136 assert(outBuf.countFrames() == audioBuffer_.getNumSamples());
137
138 /* If events are null: Audio stack processing (master in, master out or
139 sample channels. No need for MIDI events.
140 If events are not null: MIDI stack (MIDI channels). MIDI channels must not
141 process the current buffer: give them an empty and clean one. */
142
143 if (events == nullptr) {
144 giadaToJuceTempBuf_(outBuf);
145 juce::MidiBuffer dummyEvents; // empty
146 processPlugins_(pluginIds, dummyEvents);
147 }
148 else {
149 audioBuffer_.clear();
150 processPlugins_(pluginIds, *events);
151 }
152 juceToGiadaOutBuf_(outBuf);
153 }
154
155
156 /* -------------------------------------------------------------------------- */
157
158
addPlugin(std::unique_ptr<Plugin> p,ID channelId)159 void addPlugin(std::unique_ptr<Plugin> p, ID channelId)
160 {
161 ID pluginId = p->id;
162
163 model::plugins.push(std::move(p));
164
165 model::onSwap(model::channels, channelId, [&](Channel& c)
166 {
167 c.pluginIds.push_back(pluginId);
168 });
169 }
170
171
172 /* -------------------------------------------------------------------------- */
173
174
swapPlugin(ID pluginId1,ID pluginId2,ID channelId)175 void swapPlugin(ID pluginId1, ID pluginId2, ID channelId)
176 {
177 model::onSwap(model::channels, channelId, [&](Channel& c)
178 {
179 auto a = u::vector::indexOf(c.pluginIds, pluginId1);
180 auto b = u::vector::indexOf(c.pluginIds, pluginId2);
181
182 std::swap(c.pluginIds.at(a), c.pluginIds.at(b));
183 });
184 }
185
186
187 /* -------------------------------------------------------------------------- */
188
189
freePlugin(ID pluginId,ID channelId)190 void freePlugin(ID pluginId, ID channelId)
191 {
192 model::onSwap(model::channels, channelId, [&](Channel& c)
193 {
194 u::vector::remove(c.pluginIds, pluginId);
195 });
196
197 model::plugins.pop(model::getIndex(model::plugins, pluginId));
198 }
199
200
freePlugins(const std::vector<ID> & pluginIds)201 void freePlugins(const std::vector<ID>& pluginIds)
202 {
203 for (ID id : pluginIds)
204 model::plugins.pop(model::getIndex(model::plugins, id));
205 }
206
207
208 /* -------------------------------------------------------------------------- */
209
210
clonePlugins(std::vector<ID> pluginIds)211 std::vector<ID> clonePlugins(std::vector<ID> pluginIds)
212 {
213 std::vector<ID> out;
214 for (ID id : pluginIds)
215 out.push_back(clonePlugin_(id));
216 return out;
217 }
218
219
220 /* -------------------------------------------------------------------------- */
221
222
setPluginParameter(ID pluginId,int paramIndex,float value)223 void setPluginParameter(ID pluginId, int paramIndex, float value)
224 {
225 model::onGet(model::plugins, pluginId, [&](Plugin& p)
226 {
227 p.setParameter(paramIndex, value);
228 });
229 }
230
231
232 /* -------------------------------------------------------------------------- */
233
234
setPluginProgram(ID pluginId,int programIndex)235 void setPluginProgram(ID pluginId, int programIndex)
236 {
237 model::onGet(model::plugins, pluginId, [&](Plugin& p)
238 {
239 p.setCurrentProgram(programIndex);
240 });
241 }
242
243
244 /* -------------------------------------------------------------------------- */
245
246
toggleBypass(ID pluginId)247 void toggleBypass(ID pluginId)
248 {
249 model::onGet(model::plugins, pluginId, [&](Plugin& p)
250 {
251 p.setBypass(!p.isBypassed());
252 });
253 }
254
255
256 /* -------------------------------------------------------------------------- */
257
258
runDispatchLoop()259 void runDispatchLoop()
260 {
261 messageManager_->runDispatchLoopUntil(10);
262 }
263
264 }}} // giada::m::pluginHost::
265
266
267 #endif // #ifdef WITH_VST
268