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