├── .classpath
├── .gitignore
├── .project
├── README.md
├── clojurevst.jardesc
├── dist
├── clojurevst-linux.ini
├── clojurevst-linux.so
├── clojurevst-win.ini
└── clojurevst.jar
├── lib
├── clojure-contrib.jar
├── clojure.jar
├── jVSTsYstem-1.0beta.jar
└── jVSTwRapper-1.0beta.jar
├── manifest.mf
├── profiler4j-settings.p4j
└── src
└── de
└── flupp
└── clojurevst
├── ClojureVSTPluginProxy.java
├── PluginConstants.java
├── ProxyTools.java
├── config
├── ClojureVSTPluginConfig.java
├── Parameter.java
└── Program.java
└── plugins
├── 2polelp.clj
├── 2polelpset.clj
├── cljdelay.clj
├── cljgain.clj
└── cljstereogain.clj
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | ClojureVST
4 |
5 |
6 |
7 |
8 |
9 | ccw.builder
10 |
11 |
12 |
13 |
14 | org.eclipse.jdt.core.javabuilder
15 |
16 |
17 |
18 |
19 |
20 | ccw.nature
21 | org.eclipse.jdt.core.javanature
22 |
23 |
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Introduction
2 | ------------
3 |
4 | This code allows developing VST plugins in [Clojure](http://clojure.org) based on [jVSTWRapper](http://jvstwrapper.sourceforge.net/).
5 |
6 | Status
7 | ------
8 |
9 | The project is a proof of concept and not actively developed.
10 |
11 | Requirements
12 | ------------
13 |
14 | * a 32-bit JVM
15 | * a VST host
16 | * jVSTWrapper (included)
17 | * clojure (included)
18 |
19 | Installation & running
20 | ----------------------
21 |
22 | * Follow [jVSTWrapper's installation instructions](http://jvstwrapper.sourceforge.net/#installation).
23 |
24 | * Copy `lib/clojure.jar`, `lib/clojure-contrib.jar` and `dist/clojurevst.jar` to the folder where you installed jVSTWrapper.
25 |
26 | * Copy the sample config (e.g. `dist/clojurevst-win.ini`) to the folder where you installed jVSTWrapper and rename it according to your plugin's dll name. See for more information.
27 |
28 | * Copy the sample plugins from `src/de/flupp/clojurevst/plugins` to the folder where you installed jVSTWrapper. The plugin to be used is defined in the ini file:
29 |
30 | ClojureVSTPluginFile=cljdelay.clj
31 | ClojureVSTPluginNamespace=de.flupp.clojurevst.cljdelay
32 |
33 | * If `ClojureVSTPluginReload` is set to true, the *.clj files in the plugin folder are monitored for updates and reloaded upon saving.
34 |
35 | * Start your VST host and load the jVSTWrapper plugin dll.
36 |
37 | Development
38 | -----------
39 |
40 | The project includes an Eclipse project file as well as all required dependencies.
41 |
42 | Copyright Notice
43 | ----------------
44 |
45 | * "VST" is a trademark of Steinberg Media Technologies GmbH.
46 |
47 | * The code includes a copy of [opaz-plugdk's](https://github.com/thbar/opaz-plugdk) `ProxyTools` class which provides a number of helper functions.
48 |
--------------------------------------------------------------------------------
/clojurevst.jardesc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/dist/clojurevst-linux.ini:
--------------------------------------------------------------------------------
1 | ClojureVSTPluginFile=de/flupp/clojurevst/plugins/2polelpset.clj
2 | ClojureVSTPluginNamespace=de.flupp.clojurevst.clj2polelpset
3 |
4 | #ClojureVSTPluginFile=de/flupp/clojurevst/plugins/2polelp.clj
5 | #ClojureVSTPluginNamespace=de.flupp.clojurevst.clj2polelp
6 |
7 | #ClojureVSTPluginFile=de/flupp/clojurevst/plugins/cljdelay.clj
8 | #ClojureVSTPluginNamespace=de.flupp.clojurevst.cljdelay
9 |
10 | #ClojureVSTPluginFile=de/flupp/clojurevst/plugins/cljstereogain.clj
11 | #ClojureVSTPluginNamespace=de.flupp.clojurevst.cljstereogain
12 |
13 | #ClojureVSTPluginFile=de/flupp/clojurevst/plugins/cljgain.clj
14 | #ClojureVSTPluginNamespace=de.flupp.clojurevst.cljgain
15 |
16 | ClojureVSTPluginReload=true
17 |
18 | PluginClass=de/flupp/clojurevst/ClojureVSTPluginProxy
19 |
20 | #Classpath for distribution setup (notice clojurevst.jar)
21 | #ClassPath={WrapperPath}/jVSTwRapper-1.0beta.jar:{WrapperPath}/clojure.jar:{WrapperPath}/clojure-contrib.jar:{WrapperPath}/clojurevst.jar
22 |
23 | #Classpath for TEST setup (notice "../bin" --> directly use eclipse compile output)
24 | ClassPath={WrapperPath}/../lib/jVSTwRapper-1.0beta.jar:{WrapperPath}/../lib/clojure.jar:{WrapperPath}/../lib/clojure-contrib.jar:{WrapperPath}/../bin/
25 |
26 | SystemClassPath={WrapperPath}/../lib/jVSTsYstem-1.0beta.jar:{WrapperPath}/../lib/clojure.jar:{WrapperPath}/../lib/clojure-contrib.jar:{WrapperPath}/../src/
27 | IsLoggingEnabled=1
28 | AttachToNativePluginWindow=1
29 |
30 | #JVMOption1=-javaagent:/home/privat/opt/profiler4j-1.0-beta2/agent.jar
31 |
32 | #JVMOption1=-Xdebug
33 | #JVMOption2=-Xnoagent
34 | #JVMOption3=-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
35 | #JVMOption4=-Djava.compiler=NONE
36 |
37 | #JVMOption1=-Xnoclassgc
38 | #JVMOption2=-Xloggc:c:/gclog.txt
39 |
40 | #JVMOption1=-verbose:jni
41 | #JVMOption2=-Xcheck:jni
--------------------------------------------------------------------------------
/dist/clojurevst-linux.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwu/ClojureVST/26adf8681a42817a21ae25aa87b04826f3e44c73/dist/clojurevst-linux.so
--------------------------------------------------------------------------------
/dist/clojurevst-win.ini:
--------------------------------------------------------------------------------
1 | ClojureVSTPluginFile=cljdelay.clj
2 | ClojureVSTPluginNamespace=de.flupp.clojurevst.cljdelay
3 | ClojureVSTPluginReload=false
4 |
5 | PluginClass=de/flupp/clojurevst/ClojureVSTPluginProxy
6 | #PluginClass=jvst/examples/jaydlay/JayDLay
7 | #PluginUIClass=jvst/examples/jaydlay/JayDLayGUI
8 |
9 | ClassPath={WrapperPath}\jVSTwRapper-1.0beta.jar;{WrapperPath}\jVSTeXamples-1.0beta.jar;{WrapperPath}\clojure.jar;{WrapperPath}\clojure-contrib.jar;{WrapperPath}\clojurevst.jar;{WrapperPath}\profile.jar
10 | SystemClassPath={WrapperPath}\jVSTsYstem-1.0beta.jar;{WrapperPath}\clojure.jar;{WrapperPath}\clojure-contrib.jar;{WrapperPath}\profile.jar
11 | IsLoggingEnabled=1
12 | #CustomJVMLocation=C:\Program Files\Java\JDK\...
13 | #CustomJVMRegistryKey=Software\\MyCompanyName\\JavaRuntimeLocation
14 | #RequestJVMVersion=1.4
15 | AttachToNativePluginWindow=1
16 |
17 | #JVMOption1=-javaagent:profile.jar
18 | #JVMOption2=-Dprofile.properties=profile.properties
19 |
20 | #JVMOption1=-Xdebug
21 | #JVMOption2=-Xnoagent
22 | #JVMOption3=-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
23 | #JVMOption4=-Djava.compiler=NONE
24 |
25 | #JVMOption1=-Xnoclassgc
26 | #JVMOption2=-Xloggc:c:\gclog.txt
27 |
28 | #JVMOption1=-verbose:jni
29 | #JVMOption2=-Xcheck:jni
30 |
--------------------------------------------------------------------------------
/dist/clojurevst.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwu/ClojureVST/26adf8681a42817a21ae25aa87b04826f3e44c73/dist/clojurevst.jar
--------------------------------------------------------------------------------
/lib/clojure-contrib.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwu/ClojureVST/26adf8681a42817a21ae25aa87b04826f3e44c73/lib/clojure-contrib.jar
--------------------------------------------------------------------------------
/lib/clojure.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwu/ClojureVST/26adf8681a42817a21ae25aa87b04826f3e44c73/lib/clojure.jar
--------------------------------------------------------------------------------
/lib/jVSTsYstem-1.0beta.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwu/ClojureVST/26adf8681a42817a21ae25aa87b04826f3e44c73/lib/jVSTsYstem-1.0beta.jar
--------------------------------------------------------------------------------
/lib/jVSTwRapper-1.0beta.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dwu/ClojureVST/26adf8681a42817a21ae25aa87b04826f3e44c73/lib/jVSTwRapper-1.0beta.jar
--------------------------------------------------------------------------------
/manifest.mf:
--------------------------------------------------------------------------------
1 | Manifest-Version: 1.0
2 |
3 |
--------------------------------------------------------------------------------
/profiler4j-settings.p4j:
--------------------------------------------------------------------------------
1 |
2 |
3 | localhost
4 | 7890
5 |
6 | org.apache.*(*)
7 | org.jboss.*(*)
8 | net.sf.jasperreports.*(*)
9 | bsh.*(*)
10 | EDU.oswego.*(*)
11 | org.eclipse.*(*)
12 | org.hsqldb.*(*)
13 | clojure.*__init.*(*)
14 | *(*)
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/de/flupp/clojurevst/ClojureVSTPluginProxy.java:
--------------------------------------------------------------------------------
1 | package de.flupp.clojurevst;
2 |
3 | import java.io.File;
4 | import java.io.FilenameFilter;
5 | import java.util.Hashtable;
6 |
7 | import jvst.wrapper.VSTPluginAdapter;
8 | import clojure.lang.Var;
9 | import de.flupp.clojurevst.config.ClojureVSTPluginConfig;
10 |
11 | public class ClojureVSTPluginProxy extends VSTPluginAdapter {
12 |
13 | private ClojureVSTPluginConfig pluginConfig;
14 | private Var cljProcessReplacing;
15 | private boolean suspendProcessing = false;
16 | private boolean variablesBound = false;
17 |
18 | public ClojureVSTPluginProxy(long wrapper) throws Exception {
19 | super(wrapper);
20 |
21 | loadPlugin(ProxyTools.getIniFileName(ProxyTools.getResourcesFolder(getLogBasePath()), getLogFileName()));
22 | setProgram(0);
23 |
24 | if (pluginConfig.isPluginReload()) {
25 | log("Starting Watcher thread to reload plugin if any .clj file changed");
26 | new Watcher(this).start();
27 | }
28 |
29 | log("[ClojureVSTPluginProxy] Successfully loaded Clojure VST plugin " + pluginConfig.getPluginNamespace() + " from file " + pluginConfig.getPluginFilename());
30 | }
31 |
32 | public void loadPlugin(String iniFileName) throws Exception {
33 | pluginConfig = new ClojureVSTPluginConfig(iniFileName);
34 | cljProcessReplacing = pluginConfig.getProcessReplacing();
35 |
36 | setNumInputs(pluginConfig.getNumInputs());
37 | setNumOutputs(pluginConfig.getNumOutputs());
38 | canProcessReplacing(pluginConfig.canProcessReplacing());
39 | canMono(pluginConfig.canMono());
40 | setUniqueID(pluginConfig.getUniqueId());
41 | }
42 |
43 | public int canDo(String feature) {
44 | Var func = pluginConfig.getMethod(PluginConstants.METHOD_CAN_DO);
45 | if (func == null) {
46 | // use generic method implementation
47 | return pluginConfig.canDo(feature);
48 | } else {
49 | try {
50 | // use method implementation in plugin
51 | Object result = func.invoke(feature);
52 | return (Integer)result;
53 | } catch (Exception e) {
54 | log("[ClojureVSTPluginProxy::canDo] Exception during method execution");
55 | log(e.getStackTrace().toString());
56 | throw(new IllegalStateException(e));
57 | }
58 | }
59 | }
60 |
61 | public int getPlugCategory() {
62 | Var func = pluginConfig.getMethod(PluginConstants.METHOD_GET_PLUG_CATEGORY);
63 | if (func == null) {
64 | // use generic method implementation
65 | return pluginConfig.getPluginCategory();
66 | } else {
67 | try {
68 | // use method implementation in plugin
69 | Object result = func.invoke();
70 | return (Integer)result;
71 | } catch (Exception e) {
72 | log("[ClojureVSTPluginProxy::getPlugCategory] Exception during method execution");
73 | log(e.getStackTrace().toString());
74 | throw(new IllegalStateException(e));
75 | }
76 | }
77 | }
78 |
79 | public String getProductString() {
80 | Var func = pluginConfig.getMethod(PluginConstants.METHOD_GET_PRODUCT_STRING);
81 | if (func == null) {
82 | // use generic method implementation
83 | return pluginConfig.getProductString();
84 | } else {
85 | try {
86 | // use method implementation in plugin
87 | Object result = func.invoke();
88 | return result.toString();
89 | } catch (Exception e) {
90 | log("[ClojureVSTPluginProxy::getProductString] Exception during method execution");
91 | log(e.getStackTrace().toString());
92 | throw(new IllegalStateException(e));
93 | }
94 | }
95 | }
96 |
97 | // TODO Only needed if plugin supports more than one category
98 | public String getProgramNameIndexed(int arg0, int arg1) {
99 | return "TODO";
100 | }
101 |
102 | public String getVendorString() {
103 | Var func = pluginConfig.getMethod(PluginConstants.METHOD_GET_VENDOR_STRING);
104 | if (func == null) {
105 | // use generic method implementation
106 | return pluginConfig.getVendorString();
107 | } else {
108 | try {
109 | // use method implementation in plugin
110 | Object result = func.invoke();
111 | return result.toString();
112 | } catch (Exception e) {
113 | log("[ClojureVSTPluginProxy::getVendorString] Exception during method execution");
114 | log(e.getStackTrace().toString());
115 | throw(new IllegalStateException(e));
116 | }
117 | }
118 | }
119 |
120 | public boolean setBypass(boolean arg0) {
121 | // TODO Currently no support for software bypass
122 | return false;
123 | }
124 |
125 | public boolean string2Parameter(int idx, String value) {
126 | Var func = pluginConfig.getMethod(PluginConstants.METHOD_STRING2PARAMETER);
127 | if (func == null) {
128 | // use generic method implementation
129 | try {
130 | setParameter(idx, Float.parseFloat(value));
131 | return true;
132 | } catch (Exception e) {
133 | log("[ClojureVSTPluginProxy::string2Parameter] Unable to set value " + value + " for parameter index " + idx);
134 | log(e.getStackTrace().toString());
135 | throw(new IllegalStateException(e));
136 | }
137 | } else {
138 | try {
139 | // use method implementation in plugin
140 | Object result = func.invoke(idx, value);
141 | return (Boolean)result;
142 | } catch (Exception e) {
143 | log("[ClojureVSTPluginProxy::string2Parameter] Exception during method execution");
144 | log(e.getStackTrace().toString());
145 | throw(new IllegalStateException(e));
146 | }
147 | }
148 | }
149 |
150 | public int getNumParams() {
151 | Var func = pluginConfig.getMethod(PluginConstants.METHOD_GET_NUM_PARAMS);
152 | if (func == null) {
153 | // use generic method implementation
154 | return pluginConfig.getNumParams();
155 | } else {
156 | try {
157 | // use method implementation in plugin
158 | Object result = func.invoke();
159 | return (Integer)result;
160 | } catch (Exception e) {
161 | log("[ClojureVSTPluginProxy::getNumParams] Exception during method execution");
162 | log(e.getStackTrace().toString());
163 | throw(new IllegalStateException(e));
164 | }
165 | }
166 | }
167 |
168 | public int getNumPrograms() {
169 | Var func = pluginConfig.getMethod(PluginConstants.METHOD_GET_NUM_PROGRAMS);
170 | if (func == null) {
171 | // use generic method implementation
172 | return pluginConfig.getNumPrograms();
173 | } else {
174 | try {
175 | // use method implementation in plugin
176 | Object result = func.invoke();
177 | return (Integer)result;
178 | } catch (Exception e) {
179 | log("[ClojureVSTPluginProxy::getNumPrograms] Exception during method execution");
180 | log(e.getStackTrace().toString());
181 | throw(new IllegalStateException(e));
182 | }
183 | }
184 | }
185 |
186 | public float getParameter(int idx) {
187 | Var func = pluginConfig.getMethod(PluginConstants.METHOD_GET_PARAMETER);
188 | if (func == null) {
189 | // use generic method implementation
190 | return pluginConfig.getParameterFloatCached(idx);
191 | } else {
192 | try {
193 | // use method implementation in plugin
194 | Object result = func.invoke();
195 | return ((Double)result).floatValue();
196 | } catch (Exception e) {
197 | log("[ClojureVSTPluginProxy::getParameter] Exception during method execution");
198 | log(e.getStackTrace().toString());
199 | throw(new IllegalStateException(e));
200 | }
201 | }
202 | }
203 |
204 | public String getParameterDisplay(int idx) {
205 | Var func = pluginConfig.getMethod(PluginConstants.METHOD_GET_PARAMETER_DISPLAY);
206 | if (func == null) {
207 | // use generic method implementation
208 | if (pluginConfig.getParameter(idx).hasMultiplier()) {
209 | return Float.toString(pluginConfig.getParameterFloatCached(idx) * pluginConfig.getParameter(idx).getMultiplier());
210 | } else {
211 | return Float.toString(pluginConfig.getParameterFloatCached(idx));
212 | }
213 | } else {
214 | try {
215 | // use method implementation in plugin
216 | Object result = func.invoke(idx);
217 | return result.toString();
218 | } catch (Exception e) {
219 | log("[ClojureVSTPluginProxy::getParameterDisplay] Exception during method execution");
220 | log(e.getStackTrace().toString());
221 | throw(new IllegalStateException(e));
222 | }
223 | }
224 | }
225 |
226 | public String getParameterLabel(int idx) {
227 | Var func = pluginConfig.getMethod(PluginConstants.METHOD_GET_PARAMETER_LABEL);
228 | if (func == null) {
229 | // use generic method implementation
230 | return pluginConfig.getParameter(idx).getLabel();
231 | } else {
232 | try {
233 | // use method implementation in plugin
234 | Object result = func.invoke(idx);
235 | return result.toString();
236 | } catch (Exception e) {
237 | log("[ClojureVSTPluginProxy::getParameterLabel] Exception during method execution");
238 | log(e.getStackTrace().toString());
239 | throw(new IllegalStateException(e));
240 | }
241 | }
242 | }
243 |
244 | public String getParameterName(int idx) {
245 | Var func = pluginConfig.getMethod(PluginConstants.METHOD_GET_PARAMETER_NAME);
246 | if (func == null) {
247 | // use generic method implementation
248 | return pluginConfig.getParameter(idx).getName();
249 | } else {
250 | try {
251 | // use method implementation in plugin
252 | Object result = func.invoke(idx);
253 | return result.toString();
254 | } catch (Exception e) {
255 | log("[ClojureVSTPluginProxy::getParameterName] Exception during method execution");
256 | log(e.getStackTrace().toString());
257 | throw(new IllegalStateException(e));
258 | }
259 | }
260 | }
261 |
262 | public int getProgram() {
263 | Var func = pluginConfig.getMethod(PluginConstants.METHOD_GET_PROGRAM);
264 | if (func == null) {
265 | // use generic method implementation
266 | return pluginConfig.getCurrentProgram();
267 | } else {
268 | try {
269 | // use method implementation in plugin
270 | Object result = func.invoke();
271 | return (Integer)result;
272 | } catch (Exception e) {
273 | log("[ClojureVSTPluginProxy::getProgram] Exception during method execution");
274 | log(e.getStackTrace().toString());
275 | throw(new IllegalStateException(e));
276 | }
277 | }
278 | }
279 |
280 | public String getProgramName() {
281 | Var func = pluginConfig.getMethod(PluginConstants.METHOD_GET_PROGRAM_NAME);
282 | if (func == null) {
283 | // use generic method implementation
284 | return pluginConfig.getProgram(pluginConfig.getCurrentProgram()).getName();
285 | } else {
286 | try {
287 | // use method implementation in plugin
288 | Object result = func.invoke();
289 | return result.toString();
290 | } catch (Exception e) {
291 | log("[ClojureVSTPluginProxy::getProgramName] Exception during method execution");
292 | log(e.getStackTrace().toString());
293 | throw(new IllegalStateException(e));
294 | }
295 | }
296 | }
297 |
298 | public void processReplacing(float[][] inputs, float[][] outputs, int samples) {
299 | if (suspendProcessing)
300 | return;
301 | if (!variablesBound)
302 | pluginConfig.bindThreadBoundVariables();
303 |
304 | try {
305 | cljProcessReplacing.invoke(inputs, outputs);
306 | } catch (Exception e) {
307 | log("[CloureVSTPluginProxy::processReplacing] Cannot execute process-replacing.");
308 | log(ProxyTools.getStackTraceText(e));
309 | throw(new IllegalStateException(e));
310 | }
311 | }
312 |
313 | /**
314 | * Generic implementation of accumulating process. Should only be used
315 | * if the plugin does not implement "process" itself and the host
316 | * application demands for it.
317 | *
318 | * TODO: needs testing
319 | *
320 | * @see jvst.wrapper.VSTPluginAdapter#process(float[][], float[][], int)
321 | */
322 | public void process(float[][] inputs, float[][] outputs, int samples) {
323 | if (suspendProcessing)
324 | return;
325 | if (!variablesBound)
326 | pluginConfig.bindThreadBoundVariables();
327 |
328 | float[][] originalOutputs = new float[outputs.length][outputs[0].length]; //assume quadratic (note: not rectangular!) array
329 | System.arraycopy(outputs, 0, originalOutputs, 0, outputs.length);
330 |
331 | //fake process() through a call to processReplacing
332 | processReplacing(inputs, outputs, samples);
333 |
334 | // accumulate output and original output
335 | for (int i = 0; i < outputs.length; i++) {
336 | for (int j = 0; j < outputs[i].length; j++) {
337 | outputs[i][j] = outputs[i][j] + originalOutputs[i][j];
338 | outputs[i][j] = outputs[i][j] + originalOutputs[i][j];
339 | }
340 | }
341 | }
342 |
343 | public void setParameter(int idx, float value) {
344 | Var func = pluginConfig.getMethod(PluginConstants.METHOD_SET_PARAMETER);
345 | if (func == null) {
346 | // use generic method implementation
347 | pluginConfig.setParameter(idx, value);
348 | } else {
349 | try {
350 | // use method implementation in plugi
351 | func.invoke(idx, value);
352 | } catch (Exception e) {
353 | log("[ClojureVSTPluginProxy::setParameter] Exception during method execution");
354 | log(e.getStackTrace().toString());
355 | throw(new IllegalStateException(e));
356 | }
357 | }
358 | }
359 |
360 | public void setProgram(int currentProgram) {
361 | Var func = pluginConfig.getMethod(PluginConstants.METHOD_SET_PROGRAM);
362 | if (func == null) {
363 | // use generic method implementation
364 | pluginConfig.setProgram(currentProgram);
365 | } else {
366 | try {
367 | // use method implementation in plugi
368 | func.invoke(currentProgram);
369 | } catch (Exception e) {
370 | log("[ClojureVSTPluginProxy::setProgram] Exception during method execution");
371 | log(e.getStackTrace().toString());
372 | throw(new IllegalStateException(e));
373 | }
374 | }
375 | }
376 |
377 | public void setProgramName(String programName) {
378 | Var func = pluginConfig.getMethod(PluginConstants.METHOD_SET_PROGRAM_NAME);
379 | if (func == null) {
380 | // use generic method implementation
381 | pluginConfig.setCurrentProgramName(programName);
382 | } else {
383 | try {
384 | // use method implementation in plugi
385 | func.invoke(programName);
386 | } catch (Exception e) {
387 | log("[ClojureVSTPluginProxy::setProgramName] Exception during method execution");
388 | log(e.getStackTrace().toString());
389 | throw(new IllegalStateException(e));
390 | }
391 | }
392 | }
393 |
394 |
395 |
396 | private class Watcher extends Thread {
397 | Hashtable toWatch = new Hashtable();
398 |
399 | ClojureVSTPluginProxy proxy = null;
400 |
401 | public Watcher(ClojureVSTPluginProxy proxy) throws Exception {
402 | this.proxy = proxy;
403 |
404 | //find the location where we loaded the main plugin file from...
405 | File f = new File(this.getContextClassLoader().getResource(proxy.pluginConfig.getPluginFilename()).toURI()).getParentFile();
406 | log("Watching all .clj files in path: " + f + " for changes");
407 | File[] files = f.listFiles(new FilenameFilter() {
408 | public boolean accept(File dir, String name) {return name.toLowerCase().endsWith(".clj");}
409 | });
410 | for (File file : files) {
411 | toWatch.put(file, file.lastModified());
412 | }
413 | }
414 |
415 | public void run() {
416 | boolean modified = false;
417 |
418 | while(true) {
419 | try {
420 | //log("### +++ ### next round...");
421 | for (File file : toWatch.keySet()) {
422 | if (file.lastModified() > toWatch.get(file)) {
423 | log("### File: " + file.getName() + " was just modified!");
424 | toWatch.put(file, file.lastModified());
425 | modified = true;
426 | }
427 | }
428 | if (modified) reloadPlugin();
429 | modified = false;
430 | Thread.sleep(1000);
431 | }
432 | catch (Exception e) {
433 | e.printStackTrace();
434 | }
435 | }
436 | }
437 |
438 | private void reloadPlugin() throws Exception {
439 | int currentProgram = proxy.getProgram();
440 |
441 | try {
442 | log("Reloading Plugin!");
443 |
444 | proxy.suspendProcessing = true;
445 | proxy.loadPlugin(ProxyTools.getIniFileName(ProxyTools.getResourcesFolder(getLogBasePath()), getLogFileName()));
446 | proxy.setProgram(currentProgram);
447 |
448 | log("all good :-)");
449 | proxy.suspendProcessing = false;
450 | }
451 | catch (Throwable t) {
452 | log(ProxyTools.getStackTraceText(t));
453 | // enable process() calls on the old plugin again
454 | log("### Plugin problem detected, using the version that ran before. Check the error log below for details");
455 | proxy.suspendProcessing = false;
456 | }
457 | }
458 | }
459 |
460 | }
461 |
--------------------------------------------------------------------------------
/src/de/flupp/clojurevst/PluginConstants.java:
--------------------------------------------------------------------------------
1 | package de.flupp.clojurevst;
2 |
3 | public class PluginConstants {
4 |
5 | // Plugin configuration (Clojure)
6 | public static final String PLUGIN_CONFIG = "plugin-config";
7 | public static final String PLUGIN_CONFIG_CAN_DO = "can-do";
8 | public static final String PLUGIN_CONFIG_PARAMETERS = "params";
9 | public static final String PLUGIN_CONFIG_UNIQUE_ID = "unique-id";
10 | public static final String PLUGIN_CONFIG_PRODUCT_STRING = "product";
11 | public static final String PLUGIN_CONFIG_NUM_INPUTS = "num-inputs";
12 | public static final String PLUGIN_CONFIG_NUM_OUTPUTS = "num-outputs";
13 | public static final String PLUGIN_CONFIG_CAN_PROCESS_REPLACING = "can-process-replacing";
14 | public static final String PLUGIN_CONFIG_CAN_MONO = "can-mono";
15 | public static final String PLUGIN_CONFIG_VENDOR_STRING = "vendor";
16 | public static final String PLUGIN_CONFIG_PLUGIN_CATEGORY = "plugin-category";
17 | public static final String PLUGIN_CONFIG_PROGRAMS = "programs";
18 |
19 | // Plugin configuration (INI-File)
20 | public static final String INI_PLUGIN_FILENAME = "ClojureVSTPluginFile";
21 | public static final String INI_PLUGIN_NAMESPACE = "ClojureVSTPluginNamespace";
22 | public static final String INI_PLUGIN_RELOAD = "ClojureVSTPluginReload";
23 |
24 | // Parameter metadata
25 | public static final String PARAM_NAME = "parameter-name";
26 | public static final String PARAM_LABEL = "parameter-label";
27 | public static final String PARAM_MULTIPLIER = "parameter-display-multiplier";
28 | public static final String PARAM_VALUE_IN_PROGRAMS = "value-in-programs";
29 | public static final String PARAM_THREAD_BOUND = "thread-bound";
30 |
31 | // Plugin methods
32 | public static final String METHOD_PROCESS_REPLACING = "process-replacing";
33 | public static final String METHOD_GET_PARAMETER_DISPLAY = "get-parameter-display";
34 | public static final String METHOD_GET_PARAMETER_LABEL = "get-parameter-label";
35 | public static final String METHOD_CAN_DO = "can-do";
36 | public static final String METHOD_GET_PLUG_CATEGORY = "get-plug-category";
37 | public static final String METHOD_GET_PRODUCT_STRING = "get-product-string";
38 | public static final String METHOD_GET_PROGRAM_NAME_INDEXED = "get-program-name-indexed";
39 | public static final String METHOD_GET_VENDOR_STRING = "get-vendor-strin";
40 | public static final String METHOD_SET_BYPASS = "set-bypass";
41 | public static final String METHOD_STRING2PARAMETER = "string2parameter";
42 | public static final String METHOD_GET_NUM_PARAMS = "get-num-params";
43 | public static final String METHOD_GET_NUM_PROGRAMS = "get-num-programs";
44 | public static final String METHOD_GET_PARAMETER = "get-parameter";
45 | public static final String METHOD_GET_PARAMETER_NAME = "get-parameter-name";
46 | public static final String METHOD_GET_PROGRAM = "get-program";
47 | public static final String METHOD_GET_PROGRAM_NAME = "get-program-name";
48 | public static final String METHOD_SET_PARAMETER = "set-parameter";
49 | public static final String METHOD_SET_PROGRAM = "set-program";
50 | public static final String METHOD_SET_PROGRAM_NAME = "set-program-name";
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/de/flupp/clojurevst/ProxyTools.java:
--------------------------------------------------------------------------------
1 | package de.flupp.clojurevst;
2 |
3 | import java.io.PrintWriter;
4 | import java.io.StringWriter;
5 |
6 | /**
7 | * Utility class (from opaz-plugdk; https://github.com/thbar/opaz-plugdk)
8 | */
9 | public class ProxyTools {
10 | // Although I wanted to use VSTPluginAdapter.RUNNING_MAC_X instead of this, it raises AWT thread errors.
11 | // Sticking with this one for the moment.
12 | public static boolean useMacOSX() {
13 | String lcOSName = System.getProperty("os.name").toLowerCase();
14 | return lcOSName.startsWith("mac os x");
15 | }
16 |
17 | public static String getResourcesFolder(String logBasePath) {
18 | String resourcesFolder = logBasePath;
19 | if (useMacOSX()) // mac os x tweak :o
20 | resourcesFolder += "/../Resources";
21 | return resourcesFolder;
22 | }
23 |
24 | public static String getIniFileName(String resourcesFolder, String logFileName) {
25 | String iniFileName = logFileName.replaceAll("_java_stdout.txt","");
26 | if (useMacOSX())
27 | iniFileName += ".jnilib";
28 | return resourcesFolder + "/" + iniFileName + ".ini";
29 | }
30 |
31 | /**
32 | * Get stack trace of an exception as a string for logging purposes.
33 | *
34 | * @param e Exception
35 | * @return
36 | */
37 | public static String getStackTraceText(Throwable e) {
38 | StringWriter sw = new StringWriter();
39 | PrintWriter pw = new PrintWriter(sw);
40 | e.printStackTrace(pw);
41 | return sw.getBuffer().toString();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/de/flupp/clojurevst/config/ClojureVSTPluginConfig.java:
--------------------------------------------------------------------------------
1 | package de.flupp.clojurevst.config;
2 |
3 | import java.io.FileInputStream;
4 | import java.util.ArrayList;
5 | import java.util.HashMap;
6 | import java.util.List;
7 | import java.util.Map;
8 | import java.util.Properties;
9 |
10 | import jvst.wrapper.VSTPluginAdapter;
11 | import clojure.lang.APersistentMap;
12 | import clojure.lang.IPersistentMap;
13 | import clojure.lang.Keyword;
14 | import clojure.lang.PersistentVector;
15 | import clojure.lang.RT;
16 | import clojure.lang.Symbol;
17 | import clojure.lang.Var;
18 | import de.flupp.clojurevst.PluginConstants;
19 | import de.flupp.clojurevst.ProxyTools;
20 |
21 | public class ClojureVSTPluginConfig {
22 |
23 | private String pluginNamespace;
24 | private String pluginFilename;
25 | private boolean pluginReload;
26 |
27 | private int uniqueId;
28 | private String productString;
29 | private String vendorString;
30 | private String vendorVersion;
31 | private int pluginCategory;
32 | private int numInputs;
33 | private int numOutputs;
34 | private boolean canProcessReplacing;
35 | private boolean canMono;
36 | private int currentProgram;
37 |
38 | private List features;
39 | private List parameters;
40 | private List programs;
41 | private Map methods;
42 |
43 | private String iniFileName;
44 | private Var cljLoadString;
45 | private Var cljProcessReplacing;
46 | private Var cljNsPublics;
47 |
48 | public ClojureVSTPluginConfig(String iniFileName) throws Exception {
49 | features = new ArrayList();
50 | parameters = new ArrayList();
51 | programs = new ArrayList();
52 | methods = new HashMap();
53 |
54 | this.iniFileName = iniFileName;
55 |
56 | cljLoadString = RT.var("clojure.core", "load-string");
57 | cljNsPublics = RT.var("clojure.core", "ns-publics");
58 |
59 | parseIni();
60 | parseConfig();
61 | parseMethods();
62 | parseParameters();
63 |
64 | VSTPluginAdapter.log("[PluginConfig] Successfully configured plugin "
65 | + this.getPluginNamespace() + "/" + this.getPluginFilename() + "\n"
66 | + this.toString());
67 | }
68 |
69 | public Var getProcessReplacing() {
70 | return cljProcessReplacing;
71 | }
72 |
73 | public String getPluginNamespace() {
74 | return pluginNamespace;
75 | }
76 |
77 | public void setPluginNamespace(String pluginNamespace) {
78 | this.pluginNamespace = pluginNamespace;
79 | }
80 |
81 | public String getPluginFilename() {
82 | return pluginFilename;
83 | }
84 |
85 | public void setPluginFilename(String pluginFilename) {
86 | this.pluginFilename = pluginFilename;
87 | }
88 |
89 | public boolean isPluginReload() {
90 | return pluginReload;
91 | }
92 |
93 | public void setPluginReload(boolean pluginReload) {
94 | this.pluginReload = pluginReload;
95 | }
96 |
97 | public int getPluginCategory() {
98 | return pluginCategory;
99 | }
100 |
101 | public void setPluginCategory(int pluginCategory) {
102 | this.pluginCategory = pluginCategory;
103 | }
104 |
105 | public int getUniqueId() {
106 | return uniqueId;
107 | }
108 |
109 | public void setUniqueId(String uniqueId) {
110 | //extract the first 4 chars and compute a 32bit integer unique id
111 | int id = 0;
112 | for (int i=0; i values;
16 |
17 | public Parameter() {
18 | values = new ArrayList();
19 | }
20 |
21 | public Parameter(String variable, String name, String label) {
22 | this();
23 | this.variable = variable;
24 | this.name = name;
25 | this.label = label;
26 | }
27 |
28 | public String getName() {
29 | return name;
30 | }
31 |
32 | public void setName(String name) {
33 | this.name = name;
34 | }
35 |
36 | public String getLabel() {
37 | return label;
38 | }
39 |
40 | public void setLabel(String label) {
41 | this.label = label;
42 | }
43 |
44 | public String getVariableName() {
45 | return variable;
46 | }
47 |
48 | public void setVariableName(String variable) {
49 | this.variable = variable;
50 | }
51 |
52 | public float getValue(int program) {
53 | return values.get(program);
54 | }
55 |
56 | public void addValue(int program, float value) {
57 | values.add(program, value);
58 | }
59 |
60 | public void setValue(int program, float value) {
61 | values.set(program, value);
62 | }
63 |
64 | public float getMultiplier() {
65 | return multiplier;
66 | }
67 |
68 | public void setMultiplier(float multiplier) {
69 | this.multiplier = multiplier;
70 | }
71 |
72 | public void setHasMultiplier(boolean hasMultiplier) {
73 | this.bMultiplier = hasMultiplier;
74 | }
75 |
76 | public boolean hasMultiplier() {
77 | return this.bMultiplier;
78 | }
79 |
80 | public String toString()
81 | {
82 | final String TAB = " ";
83 |
84 | String retValue = "";
85 |
86 | retValue = "Parameter ( "
87 | + super.toString() + TAB
88 | + "variable = " + this.variable + TAB
89 | + "name = " + this.name + TAB
90 | + "label = " + this.label + TAB
91 | + "bMultiplier = " + this.bMultiplier + TAB
92 | + "multiplier = " + this.multiplier + TAB
93 | + "values = " + this.values + TAB
94 | + " )";
95 |
96 | return retValue;
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/src/de/flupp/clojurevst/config/Program.java:
--------------------------------------------------------------------------------
1 | package de.flupp.clojurevst.config;
2 |
3 | public class Program {
4 |
5 | private String name;
6 |
7 | public String getName() {
8 | return name;
9 | }
10 |
11 | public void setName(String name) {
12 | this.name = name;
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/de/flupp/clojurevst/plugins/2polelp.clj:
--------------------------------------------------------------------------------
1 | (ns de.flupp.clojurevst.clj2polelp)
2 |
3 | ;;Type : LP 2-pole resonant tweaked butterworth
4 | ;;References : Posted by daniel_jacob_werner [AT] yaho [DOT] com [DOT] au
5 |
6 | ;;Notes :
7 | ;This algorithm is a modified version of the tweaked butterworth lowpass filter by Patrice Tarrabia posted on musicdsp.org's archives.
8 | ;It calculates the coefficients for a second order IIR filter. The resonance is specified in decibels above the DC gain.
9 | ;It can be made suitable to use as a SoundFont 2.0 filter by scaling the output so the overall gain matches the specification
10 | ;(i.e. if resonance is 6dB then you should scale the output by -3dB). Note that you can replace the sqrt(2) values in the standard
11 | ;butterworth highpass algorithm with my "q =" line of code to get a highpass also.
12 | ;
13 | ;How it works: normally q is the constant sqrt(2), and this value controls resonance. At sqrt(2) resonance is 0dB, smaller values
14 | ;increase resonance. By multiplying sqrt(2) by a power ratio we can specify the resonant gain at the cutoff frequency.
15 | ;The resonance power ratio is calculated with a standard formula to convert between decibels and power ratios (the powf statement...).
16 | ;Good Luck,
17 | ;Daniel Werner
18 | ;http://experimentalscene.com/
19 |
20 | ;Code :
21 | ;float c, csq, resonance, q, a0, a1, a2, b1, b2;
22 |
23 | ;c = 1.0f / (tanf(pi * (cutoff / samplerate)));
24 | ;csq = c * c;
25 | ;resonance = powf(10.0f, -(resonancedB * 0.1f));
26 | ;q = sqrt(2.0f) * resonance;
27 | ;a0 = 1.0f / (1.0f + (q * c) + (csq));
28 | ;a1 = 2.0f * a0;
29 | ;a2 = a0;
30 | ;b1 = (2.0f * a0) * (1.0f - csq);
31 | ;b2 = a0 * (1.0f - (q * c) + csq);
32 |
33 | ;;TODO: this is a quite literal conversion from the original algorithm, needs clojurization (use atoms and let special form).
34 |
35 |
36 | ;; config
37 | (def plugin-config {:plugin-category 1
38 | :unique-id "2plp"
39 | :product "clj2plp"
40 | :num-inputs 2
41 | :num-outputs 2
42 | :can-process-replacing true
43 | :can-mono false
44 | :vendor "clojurevst"
45 | :can-do ["2in2out", "plugAsChannelInsert", "plugAsSend"]})
46 |
47 | ;; parameters
48 | (def #^{:parameter-name "Cutoff"
49 | :parameter-label "hz"}
50 | p1 0.04)
51 | (def #^{:parameter-name "Max Cutoff"
52 | :parameter-label "hz"}
53 | p3 0.81)
54 | (def #^{:parameter-name "Resonance"
55 | :parameter-label "db"}
56 | p2 0.81)
57 | (def #^{:parameter-name "Fine Reso"
58 | :parameter-label "db"}
59 | p4 0.9)
60 |
61 | ;;globals
62 | ;constants
63 | (def p1filtercoeff 0.0007)
64 | (def pi 3.1415926535897932384626433832795)
65 |
66 | ;thread-local vars (use thread-local bindings for them?)
67 | (def p1smooth 0.0)
68 | (def c 0.0)
69 | (def csq 0.0)
70 | (def q 0.0)
71 | (def a0 0.0)
72 | (def a1 0.0)
73 | (def a2 0.0)
74 | (def b1 0.0)
75 | (def b2 0.0)
76 |
77 | ;state maintained across process() calls
78 | (def out11 0.0)
79 | (def out12 0.0)
80 | (def in11 0.0)
81 | (def in12 0.0)
82 | (def out21 0.0)
83 | (def out22 0.0)
84 | (def in21 0.0)
85 | (def in22 0.0)
86 |
87 |
88 | ;; effect
89 | (defn process-replacing [inputs outputs]
90 | (let [in1 (nth inputs 0)
91 | in2 (nth inputs 1)
92 | out1 (nth outputs 0)
93 | out2 (nth outputs 1)
94 | samples (count out1)]
95 | (dotimes [i samples]
96 | (when (= (mod i 20) 0) ;audible param change "lag"
97 | (def p1smooth (+ (* p1filtercoeff p1) (* (- 1.0 p1filtercoeff) p1smooth))) ;parameter smoothing
98 | (def c (/ 1.0 (. java.lang.Math (tan (* pi (/ (+ 0.001 (* p1smooth p3)) 2.15))))))
99 | (def csq (* c c))
100 | (def q (* (. java.lang.Math (sqrt 2.0)) (- 1.0 p2) (- 1.0 p4)))
101 | (def a0 (/ 1.0 (+ 1.0 (* q c) csq)))
102 | (def a1 (* 2.0 a0))
103 | (def a2 a0)
104 | (def b1 (* (* 2.0 a0) (- 1.0 csq)))
105 | (def b2 (* a0 (+ (- 1.0 (* c q)) csq))))
106 | (aset-float out1 i (- (+ (* (nth in1 i) a0) (* in11 a1) (* in12 a2)) (* out11 b1) (* out12 b2)))
107 | (aset-float out2 i (- (+ (* (nth in2 i) a0) (* in21 a1) (* in22 a2)) (* out21 b1) (* out22 b2)))
108 | (def out12 out11) ;cascade
109 | (def out11 (nth out1 i))
110 | (def in12 in11)
111 | (def in11 (nth in1 i))
112 | (def out22 out21)
113 | (def out21 (nth out2 i))
114 | (def in22 in21)
115 | (def in21 (nth in2 i)))))
116 |
--------------------------------------------------------------------------------
/src/de/flupp/clojurevst/plugins/2polelpset.clj:
--------------------------------------------------------------------------------
1 | (ns de.flupp.clojurevst.clj2polelpset)
2 |
3 | ;;Type : LP 2-pole resonant tweaked butterworth
4 | ;;References : Posted by daniel_jacob_werner [AT] yaho [DOT] com [DOT] au
5 |
6 | ;;Notes :
7 | ;This algorithm is a modified version of the tweaked butterworth lowpass filter by Patrice Tarrabia posted on musicdsp.org's archives.
8 | ;It calculates the coefficients for a second order IIR filter. The resonance is specified in decibels above the DC gain.
9 | ;It can be made suitable to use as a SoundFont 2.0 filter by scaling the output so the overall gain matches the specification
10 | ;(i.e. if resonance is 6dB then you should scale the output by -3dB). Note that you can replace the sqrt(2) values in the standard
11 | ;butterworth highpass algorithm with my "q =" line of code to get a highpass also.
12 | ;
13 | ;How it works: normally q is the constant sqrt(2), and this value controls resonance. At sqrt(2) resonance is 0dB, smaller values
14 | ;increase resonance. By multiplying sqrt(2) by a power ratio we can specify the resonant gain at the cutoff frequency.
15 | ;The resonance power ratio is calculated with a standard formula to convert between decibels and power ratios (the powf statement...).
16 | ;Good Luck,
17 | ;Daniel Werner
18 | ;http://experimentalscene.com/
19 |
20 | ;Code :
21 | ;float c, csq, resonance, q, a0, a1, a2, b1, b2;
22 |
23 | ;c = 1.0f / (tanf(pi * (cutoff / samplerate)));
24 | ;csq = c * c;
25 | ;resonance = powf(10.0f, -(resonancedB * 0.1f));
26 | ;q = sqrt(2.0f) * resonance;
27 | ;a0 = 1.0f / (1.0f + (q * c) + (csq));
28 | ;a1 = 2.0f * a0;
29 | ;a2 = a0;
30 | ;b1 = (2.0f * a0) * (1.0f - csq);
31 | ;b2 = a0 * (1.0f - (q * c) + csq);
32 |
33 | ;;TODO: this is a quite literal conversion from the original algorithm, needs clojurization (use atoms and let special form).
34 |
35 | ;; config
36 | (def plugin-config {:plugin-category 1
37 | :unique-id "2plp"
38 | :product "clj2plp"
39 | :num-inputs 2
40 | :num-outputs 2
41 | :can-process-replacing true
42 | :can-mono false
43 | :vendor "clojurevst"
44 | :can-do ["2in2out", "plugAsChannelInsert", "plugAsSend"]})
45 |
46 | ;; parameters
47 | (def #^{:parameter-name "Cutoff"
48 | :parameter-label "hz"}
49 | p1 0.04)
50 | (def #^{:parameter-name "Max Cutoff"
51 | :parameter-label "hz"}
52 | p3 0.81)
53 | (def #^{:parameter-name "Resonance"
54 | :parameter-label "db"}
55 | p2 0.81)
56 | (def #^{:parameter-name "Fine Reso"
57 | :parameter-label "db"}
58 | p4 0.9)
59 |
60 | ;;globals
61 | (def #^{:thread-bound 1} p1smooth 1.0)
62 | (def #^{:thread-bound 1} p1filtercoeff 0.0007)
63 | (def pi 3.1415926535897932384626433832795)
64 | (def #^{:thread-bound 1} out11 0.0)
65 | (def #^{:thread-bound 1} out12 0.0)
66 | (def #^{:thread-bound 1} in11 0.0)
67 | (def #^{:thread-bound 1} in12 0.0)
68 | (def #^{:thread-bound 1} out21 0.0)
69 | (def #^{:thread-bound 1} out22 0.0)
70 | (def #^{:thread-bound 1} in21 0.0)
71 | (def #^{:thread-bound 1} in22 0.0)
72 | (def #^{:thread-bound 1} c 0.0)
73 | (def #^{:thread-bound 1} csq 0.0)
74 | (def #^{:thread-bound 1} q 0.0)
75 | (def #^{:thread-bound 1} a0 0.0)
76 | (def #^{:thread-bound 1} a1 0.0)
77 | (def #^{:thread-bound 1} a2 0.0)
78 | (def #^{:thread-bound 1} b1 0.0)
79 | (def #^{:thread-bound 1} b2 0.0)
80 |
81 | ;; effect
82 | (defn process-replacing [inputs outputs]
83 | (let [in1 (nth inputs 0)
84 | in2 (nth inputs 1)
85 | out1 (nth outputs 0)
86 | out2 (nth outputs 1)
87 | samples (count out1)]
88 | (dotimes [i samples]
89 | (when (= (mod i 20) 0) ;audible param change "lag"
90 | (set! p1smooth (+ (* p1filtercoeff p1) (* (- 1.0 p1filtercoeff) p1smooth))) ;parameter smoothing
91 | (set! c (/ 1.0 (. java.lang.Math (tan (* pi (/ (+ 0.001 (* p1smooth p3)) 2.15))))))
92 | (set! csq (* c c))
93 | (set! q (* (. java.lang.Math (sqrt 2.0)) (- 1.0 p2) (- 1.0 p4)))
94 | (set! a0 (/ 1.0 (+ 1.0 (* q c) csq)))
95 | (set! a1 (* 2.0 a0))
96 | (set! a2 a0)
97 | (set! b1 (* (* 2.0 a0) (- 1.0 csq)))
98 | (set! b2 (* a0 (+ (- 1.0 (* c q)) csq))))
99 | (aset-float out1 i (- (+ (* (nth in1 i) a0) (* in11 a1) (* in12 a2)) (* out11 b1) (* out12 b2)))
100 | (aset-float out2 i (- (+ (* (nth in2 i) a0) (* in21 a1) (* in22 a2)) (* out21 b1) (* out22 b2)))
101 | (set! out12 out11)
102 | (set! out11 (nth out1 i))
103 | (set! in12 in11)
104 | (set! in11 (nth in1 i))
105 | (set! out22 out21)
106 | (set! out21 (nth out2 i))
107 | (set! in22 in21)
108 | (set! in21 (nth in2 i)))))
109 |
--------------------------------------------------------------------------------
/src/de/flupp/clojurevst/plugins/cljdelay.clj:
--------------------------------------------------------------------------------
1 | (ns de.flupp.clojurevst.cljdelay)
2 |
3 | ;; config
4 | (def plugin-config {:plugin-category 1
5 | :unique-id "cljD"
6 | :product "cljdelay"
7 | :num-inputs 1
8 | :num-outputs 1
9 | :can-process-replacing true
10 | :can-mono true
11 | :vendor "clojurevst"
12 | :can-do ["1in1out", "plugAsChannelInsert", "plugAsSend"]})
13 |
14 | ;; parameters
15 | (def #^{:parameter-name "Delay"
16 | :parameter-label ""
17 | :parameter-display-multiplier 44099}
18 | pdelay 0.5)
19 | (def #^{:parameter-name "Feedback"
20 | :parameter-label ""}
21 | pfeedback 0.9)
22 | (def #^{:parameter-name "Out"
23 | :parameter-label ""}
24 | pout 0.5)
25 |
26 | (def cursor (atom 0))
27 | (def buffer (make-array Float/TYPE 44100))
28 |
29 | ;; effect
30 | (defn process-replacing [inputs outputs]
31 | (let [input (nth inputs 0)
32 | samples (count input)
33 | output (nth outputs 0)]
34 | (dotimes [i samples]
35 | (aset-float output i (* pout (nth buffer @cursor)))
36 | (aset-float buffer @cursor (+ (nth input i) (* (nth output i) pfeedback)))
37 | (swap! cursor inc)
38 | (if (>= @cursor (* pdelay 44099))
39 | (reset! cursor 0)))))
--------------------------------------------------------------------------------
/src/de/flupp/clojurevst/plugins/cljgain.clj:
--------------------------------------------------------------------------------
1 | (ns de.flupp.clojurevst.cljgain)
2 |
3 | ;; config
4 | (def plugin-config {:plugin-category 1
5 | :unique-id "cljG"
6 | :product "cljgain"
7 | :num-inputs 1
8 | :num-outputs 1
9 | :can-process-replacing true
10 | :can-mono true
11 | :vendor "clojurevst"
12 | :can-do ["1in1out", "plugAsChannelInsert", "plugAsSend"]
13 | :programs ["foo", "bar"] })
14 |
15 | ;; parameters
16 | (def #^{:parameter-name "Gain"
17 | :parameter-label ""
18 | :value-in-programs [0.5, 0.9] }
19 | pgain 0.5)
20 |
21 | (defn get-parameter-display [param]
22 | (str (* pgain 10)))
23 |
24 | (defn get-parameter-label [param]
25 | (str "bla"))
26 |
27 | ;; effect processing
28 | (defn process-replacing [inputs outputs]
29 | (let [input (nth inputs 0)
30 | samples (count input)
31 | output (nth outputs 0)]
32 | (dotimes [i samples]
33 | (aset-float output i (* pgain (nth input i))))))
--------------------------------------------------------------------------------
/src/de/flupp/clojurevst/plugins/cljstereogain.clj:
--------------------------------------------------------------------------------
1 | (ns de.flupp.clojurevst.cljstereogain)
2 |
3 | ;; config
4 | (def plugin-config {:plugin-category 1
5 | :unique-id "clsG"
6 | :product "cljstereogain"
7 | :num-inputs 2
8 | :num-outputs 2
9 | :can-process-replacing true
10 | :can-mono false
11 | :vendor "clojurevst"
12 | :can-do ["2in2out", "plugAsChannelInsert", "plugAsSend"]
13 | :programs ["foo", "bar"] })
14 |
15 | ;; parameters
16 | (def #^{:parameter-name "Gain"
17 | :parameter-label ""
18 | :value-in-programs [0.5, 0.9] }
19 | pgain 0.5)
20 |
21 | (defn get-parameter-display [param]
22 | (str (* pgain 10)))
23 |
24 | (defn get-parameter-label [param]
25 | (str "bla"))
26 |
27 | ;; effect processing
28 | (defn process-replacing [inputs outputs]
29 | (let [in1 (nth inputs 0)
30 | in2 (nth inputs 1)
31 | out1 (nth outputs 0)
32 | out2 (nth outputs 1)
33 | samples (count in1)]
34 | (dotimes [i samples]
35 | (aset-float out1 i (* pgain (nth in1 i)))
36 | (aset-float out2 i (* pgain (nth in2 i))))))
37 |
--------------------------------------------------------------------------------