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