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
31 #include <cassert>
32 #include <FL/Fl.H>
33 #include "utils/log.h"
34 #include "utils/time.h"
35 #include "core/const.h"
36 #include "core/plugins/pluginManager.h"
37 #include "plugin.h"
38
39
40 using std::string;
41
42
43 namespace giada {
44 namespace m
45 {
Plugin(ID id,const std::string & UID)46 Plugin::Plugin(ID id, const std::string& UID)
47 : id (id)
48 , valid (false)
49 , onEditorResize(nullptr)
50 , m_plugin (nullptr)
51 , m_UID (UID)
52 {
53 }
54
55
56 /* -------------------------------------------------------------------------- */
57
58
Plugin(ID id,std::unique_ptr<juce::AudioPluginInstance> plugin,double samplerate,int buffersize)59 Plugin::Plugin(ID id, std::unique_ptr<juce::AudioPluginInstance> plugin, double samplerate,
60 int buffersize)
61 : id (id)
62 , valid (true)
63 , onEditorResize(nullptr)
64 , m_plugin (std::move(plugin))
65 , m_bypass (false)
66 {
67 /* (1) Initialize midiInParams vector, where midiInParams.size == number of
68 plugin parameters. All values are initially empty (0x0): they will be filled
69 during MIDI learning process. */
70
71 for (int i = 0; i < m_plugin->getParameters().size(); i++)
72 midiInParams.emplace_back(0x0, i);
73
74 m_buffer.setSize(G_MAX_IO_CHANS, buffersize);
75
76 /* Try to set the main bus to the current number of channels. In the future
77 this setup will be performed manually through a proper channel matrix. */
78
79 juce::AudioProcessor::Bus* outBus = getMainBus(BusType::OUT);
80 juce::AudioProcessor::Bus* inBus = getMainBus(BusType::IN);
81 if (outBus != nullptr) outBus->setNumberOfChannels(G_MAX_IO_CHANS);
82 if (inBus != nullptr) inBus->setNumberOfChannels(G_MAX_IO_CHANS);
83
84 m_plugin->prepareToPlay(samplerate, buffersize);
85
86 u::log::print("[Plugin] plugin initialized and ready. MIDI input params: %lu\n",
87 midiInParams.size());
88 }
89
90
91 /* -------------------------------------------------------------------------- */
92
93
Plugin(const Plugin & o)94 Plugin::Plugin(const Plugin& o)
95 : id (o.id)
96 , midiInParams (o.midiInParams)
97 , valid (o.valid)
98 , onEditorResize(o.onEditorResize)
99 , m_plugin (std::move(pluginManager::makePlugin(o)->m_plugin))
100 , m_bypass (o.m_bypass.load())
101 {
102 }
103
104
105 /* -------------------------------------------------------------------------- */
106
107
~Plugin()108 Plugin::~Plugin()
109 {
110 if (!valid)
111 return;
112
113 juce::AudioProcessorEditor* e = m_plugin->getActiveEditor();
114 if (e != nullptr)
115 e->removeComponentListener(this);
116
117 m_plugin->suspendProcessing(true);
118 m_plugin->releaseResources();
119 }
120
121
122 /* -------------------------------------------------------------------------- */
123
124
componentMovedOrResized(juce::Component & c,bool moved,bool)125 void Plugin::componentMovedOrResized(juce::Component& c, bool moved, bool/* resized*/)
126 {
127 if (moved)
128 return;
129 if (onEditorResize != nullptr)
130 onEditorResize(c.getWidth(), c.getHeight());
131 }
132
133
134 /* -------------------------------------------------------------------------- */
135
136
getMainBus(BusType b) const137 juce::AudioProcessor::Bus* Plugin::getMainBus(BusType b) const
138 {
139 const bool isInput = static_cast<bool>(b);
140 for (int i=0; i<m_plugin->getBusCount(isInput); i++)
141 if (m_plugin->getBus(isInput, i)->isMain())
142 return m_plugin->getBus(isInput, i);
143 return nullptr;
144 }
145
146
countMainOutChannels() const147 int Plugin::countMainOutChannels() const
148 {
149 juce::AudioProcessor::Bus* b = getMainBus(BusType::OUT);
150 assert(b != nullptr);
151 return b->getNumberOfChannels();
152 }
153
154
155 /* -------------------------------------------------------------------------- */
156
157
createEditor() const158 juce::AudioProcessorEditor* Plugin::createEditor() const
159 {
160 juce::AudioProcessorEditor* e = m_plugin->createEditorIfNeeded();
161 if (e != nullptr)
162 e->addComponentListener(const_cast<Plugin*>(this));
163 return e;
164 }
165
166
167 /* -------------------------------------------------------------------------- */
168
169
getUniqueId() const170 string Plugin::getUniqueId() const
171 {
172 if (!valid)
173 return m_UID;
174 return m_plugin->getPluginDescription().createIdentifierString().toStdString();
175 }
176
177
178 /* -------------------------------------------------------------------------- */
179
180
getNumParameters() const181 int Plugin::getNumParameters() const
182 {
183 return valid ? m_plugin->getParameters().size() : 0;
184 }
185
186
187 /* -------------------------------------------------------------------------- */
188
189
getParameter(int paramIndex) const190 float Plugin::getParameter(int paramIndex) const
191 {
192 return m_plugin->getParameters()[paramIndex]->getValue();
193 }
194
195
196 /* -------------------------------------------------------------------------- */
197
198
setParameter(int paramIndex,float value) const199 void Plugin::setParameter(int paramIndex, float value) const
200 {
201 m_plugin->getParameters()[paramIndex]->setValue(value);
202 }
203
204
205 /* -------------------------------------------------------------------------- */
206
207
getName() const208 string Plugin::getName() const
209 {
210 if (!valid)
211 return "** invalid **";
212 return m_plugin->getName().toStdString();
213 }
214
215
216 /* -------------------------------------------------------------------------- */
217
218
isSuspended() const219 bool Plugin::isSuspended() const
220 {
221 if (!valid)
222 return false;
223 return m_plugin->isSuspended();
224 }
225
226
227 /* -------------------------------------------------------------------------- */
228
229
acceptsMidi() const230 bool Plugin::acceptsMidi() const
231 {
232 if (!valid)
233 return false;
234 return m_plugin->acceptsMidi();
235 }
236
237
238 /* -------------------------------------------------------------------------- */
239
240
getState() const241 PluginState Plugin::getState() const
242 {
243 juce::MemoryBlock data;
244 m_plugin->getStateInformation(data);
245 return PluginState(std::move(data));
246 }
247
248
249 /* -------------------------------------------------------------------------- */
250
251
isBypassed() const252 bool Plugin::isBypassed() const { return m_bypass.load(); }
setBypass(bool b)253 void Plugin::setBypass(bool b) { m_bypass.store(b); }
254
255
256 /* -------------------------------------------------------------------------- */
257
258
process(juce::AudioBuffer<float> & out,juce::MidiBuffer m)259 void Plugin::process(juce::AudioBuffer<float>& out, juce::MidiBuffer m)
260 {
261 /* If this is not an instrument (i.e. doesn't accept MIDI), copy the
262 incoming buffer data into the temporary one. This way FXes will process
263 existing audio data. Conversely, if the plug-in is an instrument, it
264 generates its own audio data inside a clean m_buffer and we can play more
265 than one plug-in instrument in the same stack, driven by the same set of
266 MIDI events. */
267
268 const bool isInstrument = m_plugin->acceptsMidi();
269
270 if (!isInstrument)
271 m_buffer = out;
272 else
273 m_buffer.clear();
274
275 m_plugin->processBlock(m_buffer, m);
276
277 /* The local buffer is now filled. Let's try to fill the 'out' one as well
278 by taking into account the bus layout - many plug-ins might have mono output
279 and we have a stereo buffer to fill. */
280
281 for (int i=0, j=0; i<out.getNumChannels(); i++) {
282 if (isInstrument)
283 out.addFrom(i, 0, m_buffer, j, 0, m_buffer.getNumSamples());
284 else
285 out.copyFrom(i, 0, m_buffer, j, 0, m_buffer.getNumSamples());
286 if (i < countMainOutChannels() - 1)
287 j++;
288 }
289 }
290
291
292 /* -------------------------------------------------------------------------- */
293
294
setState(PluginState state)295 void Plugin::setState(PluginState state)
296 {
297 m_plugin->setStateInformation(state.getData(), state.getSize());
298 }
299
300
301 /* -------------------------------------------------------------------------- */
302
303
getNumPrograms() const304 int Plugin::getNumPrograms() const
305 {
306 if (!valid)
307 return 0;
308 return m_plugin->getNumPrograms();
309 }
310
311
312 /* -------------------------------------------------------------------------- */
313
314
getCurrentProgram() const315 int Plugin::getCurrentProgram() const
316 {
317 if (!valid)
318 return 0;
319 return m_plugin->getCurrentProgram();
320 }
321
322
323 /* -------------------------------------------------------------------------- */
324
325
setCurrentProgram(int index) const326 void Plugin::setCurrentProgram(int index) const
327 {
328 if (valid)
329 m_plugin->setCurrentProgram(index);
330 }
331
332
333 /* -------------------------------------------------------------------------- */
334
335
hasEditor() const336 bool Plugin::hasEditor() const
337 {
338 if (!valid)
339 return false;
340 return m_plugin->hasEditor();
341 }
342
343
344 /* -------------------------------------------------------------------------- */
345
346
getProgramName(int index) const347 string Plugin::getProgramName(int index) const
348 {
349 if (!valid)
350 return {};
351 return m_plugin->getProgramName(index).toStdString();
352 }
353
354
355 /* -------------------------------------------------------------------------- */
356
357
getParameterName(int index) const358 string Plugin::getParameterName(int index) const
359 {
360 if (!valid)
361 return {};
362 const int labelSize = 64;
363 return m_plugin->getParameters()[index]->getName(labelSize).toStdString();
364 }
365
366
367 /* -------------------------------------------------------------------------- */
368
369
getParameterText(int index) const370 string Plugin::getParameterText(int index) const
371 {
372 return m_plugin->getParameters()[index]->getCurrentValueAsText().toStdString();
373 }
374
375
376 /* -------------------------------------------------------------------------- */
377
378
getParameterLabel(int index) const379 string Plugin::getParameterLabel(int index) const
380 {
381 return m_plugin->getParameters()[index]->getLabel().toStdString();
382 }
383
384 }} // giada::m::
385
386
387 #endif
388