2 terminatorX - realtime audio scratching software
3 Copyright (C) 1999-2016 Alexander König
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 Description: This handles the effects in the per vtt fx chain. Supports the
21 buitlin echo/lowpass effects and ladspa plugins.
28 #define myvtt ((vtt_class *) vtt)
29 #include "tX_global.h"
32 float ladspa_dummy_output_port;
34 void vtt_fx :: reconnect_buffer()
39 vtt_fx :: ~vtt_fx() {}
40 void vtt_fx::toggle_drywet() {}
41 bool vtt_fx::is_stereo() { return false; }
42 tX_drywet_type vtt_fx::has_drywet_feature() { return NOT_DRYWET_CAPABLE; }
44 /******************* builtin fx ***/
47 void vtt_fx_lp :: activate() { myvtt->lp_reset(); }
48 void vtt_fx_lp :: deactivate() { /* NOP */ }
49 void vtt_fx_lp :: run() { myvtt->render_lp(); }
50 int vtt_fx_lp :: isEnabled() { return myvtt->lp_enable; }
52 void vtt_fx_lp :: save (FILE *rc, gzFile rz, char *indent) {
53 tX_store("%s<cutoff/>\n", indent);
57 const char *vtt_fx_lp :: get_info_string()
59 return "TerminatorX built-in resonant lowpass filter.";
64 void vtt_fx_ec :: activate() { /* NOP */ }
65 void vtt_fx_ec :: deactivate() { myvtt->ec_clear_buffer(); }
66 void vtt_fx_ec :: run() { myvtt->render_ec(); }
67 int vtt_fx_ec :: isEnabled() { return myvtt->ec_enable; }
69 void vtt_fx_ec :: save (FILE *rc, gzFile rz, char *indent) {
70 tX_store("%s<lowpass/>\n", indent);
73 const char *vtt_fx_ec :: get_info_string()
75 return "TerminatorX built-in echo effect.";
78 /******************** LADSPA fx ***/
79 /* short cut "cpd" macro to current port descriptor */
81 #define cpd plugin->getDescriptor()->PortDescriptors[port]
82 #define cpn plugin->getDescriptor()->PortNames[port]
83 #define cph plugin->getDescriptor()->PortRangeHints[port]
85 void vtt_fx_ladspa :: reconnect_buffer()
87 plugin->getDescriptor()->connect_port(instance, input_port, myvtt->output_buffer);
89 plugin->getDescriptor()->connect_port(instance, output_port, wet_buffer);
91 plugin->getDescriptor()->connect_port(instance, output_port, myvtt->output_buffer);
95 static void wrapstr(char *str)
101 token=strtok(str, " ");
105 if (strlen(token)+strlen(temp)<10)
107 if (strlen(temp)) strcat(temp, " ");
114 if(strlen(target)) strcat(target, "\n");
122 strcat(target, temp);
126 token=strtok(NULL, " ");
131 if(strlen(target)) strcat(target, "\n");
132 strcat(target, temp);
138 vtt_fx_ladspa :: vtt_fx_ladspa(LADSPA_Plugin *p, void *v)
149 instance=(LADSPA_Handle *) plugin->getDescriptor()->instantiate(plugin->getDescriptor(), 44100);
153 fprintf (stderr, "tX: Fatal Error: failed to instantiate plugin \"%s\".\n", plugin->getDescriptor()->Name);
154 /* How to handle this ? */
157 sp = sp_enable = new tX_seqpar_vttfx_bool();
158 sp->set_mapping_parameters(1, 0, 0, 0);
159 sprintf(buffer, "%s: Enable", plugin->getName());
160 sp->set_name(buffer, "Enable");
162 controls.push_back(sp);
167 /* connecting ports */
168 for (port=0; port < plugin->getPortCount(); port++) {
169 if (LADSPA_IS_PORT_AUDIO(cpd)) {
170 if (LADSPA_IS_PORT_INPUT(cpd)) input_port=port;
171 else if (LADSPA_IS_PORT_OUTPUT(cpd)) output_port=port;
172 } else if ((LADSPA_IS_PORT_CONTROL(cpd)) && (LADSPA_IS_PORT_INPUT(cpd))) {
176 tX_debug("vtt_fx_ladspa(): wiring %s for %s", cpn, plugin->getLabel());
177 tX_debug("vtt_fx_ladspa(): bound below: %s, %8lf.", LADSPA_IS_HINT_BOUNDED_BELOW(cph.HintDescriptor) ? "yes": "no", cph.LowerBound);
178 tX_debug("vtt_fx_ladspa(): bound above: %s, %8lf.", LADSPA_IS_HINT_BOUNDED_ABOVE(cph.HintDescriptor) ? "yes": "no", cph.UpperBound);
180 if (LADSPA_IS_HINT_BOUNDED_BELOW(cph.HintDescriptor)) min=cph.LowerBound;
181 if (LADSPA_IS_HINT_BOUNDED_ABOVE(cph.HintDescriptor)) max=cph.UpperBound;
183 if (LADSPA_IS_HINT_SAMPLE_RATE(cph.HintDescriptor)) {
184 tX_debug("vtt_fx_ladspa(): is sample rate");
185 min*=44100; max*=44100;
188 if (LADSPA_IS_HINT_TOGGLED(cph.HintDescriptor)) {
189 tX_debug("vtt_fx_ladspa(): bool seqpar - min: %f, max %f", min, max);
190 sp=new tX_seqpar_vttfx_bool();
191 sp->set_mapping_parameters(max, min, 0, 0);
192 } else if (LADSPA_IS_HINT_INTEGER(cph.HintDescriptor)) {
193 tX_debug("vtt_fx_ladspa(): int seqpar - min: %f, max %f", min, max);
194 sp=new tX_seqpar_vttfx_int();
195 sp->set_mapping_parameters(max, min, 0, 0);
197 tX_debug("vtt_fx_ladspa(): float seqpar - min: %f, max %f", min, max);
198 sp=new tX_seqpar_vttfx_float();
199 sp->set_mapping_parameters(max, min, (max-min)/100.0, 1);
202 sprintf(buffer, "%s: %s", plugin->getLabel(), cpn);
203 strcpy(buffer2, cpn);
206 sp->set_name(buffer, buffer2);
208 plugin->getDescriptor()->connect_port(instance, port, sp->get_value_ptr());
209 controls.push_back(sp);
210 } else if ((LADSPA_IS_PORT_CONTROL(cpd)) && (LADSPA_IS_PORT_OUTPUT(cpd))) {
211 plugin->getDescriptor()->connect_port(instance, port, &ladspa_dummy_output_port);
216 void vtt_fx_ladspa :: realloc_drywet()
219 wet_buffer=(f_prec *) malloc(sizeof(float)*vtt_class::samples_in_mix_buffer);
222 void vtt_fx_ladspa :: free_drywet()
230 void vtt_fx_ladspa :: activate()
235 reconnect_buffer(); // we always have to reconnect...
236 if (plugin->getDescriptor()->activate) plugin->getDescriptor()->activate(instance);
239 void vtt_fx_ladspa :: deactivate()
241 if (plugin->getDescriptor()->deactivate) plugin->getDescriptor()->deactivate(instance);
246 void vtt_fx_ladspa :: run()
248 plugin->getDescriptor()->run(instance, (vtt_class::samples_in_mix_buffer)>>1);
251 f_prec wet=sp_wet->get_value();
254 for (unsigned int sample=0; sample < (vtt_class::samples_in_mix_buffer)>>1; sample++) {
255 myvtt->output_buffer[sample]=dry*myvtt->output_buffer[sample]+wet*wet_buffer[sample];
260 int vtt_fx_ladspa :: isEnabled()
262 return (int) sp_enable->get_value();
265 const char *vtt_fx_ladspa :: get_info_string()
267 return plugin->get_info_string();
270 vtt_fx_ladspa :: ~vtt_fx_ladspa()
272 list <tX_seqpar_vttfx *> :: iterator sp;
274 while (controls.size()) {
276 controls.remove((*sp));
280 plugin->getDescriptor()->cleanup(instance);
282 if (wet_buffer) free(wet_buffer);
287 void vtt_fx_ladspa :: save (FILE *rc, gzFile rz, char *indent) {
288 long ID=plugin->getUniqueID();
289 list <tX_seqpar_vttfx *> :: iterator sp;
291 tX_store("%s<ladspa_plugin>\n", indent);
292 strcat (indent, "\t");
294 store_int("ladspa_id", ID);
295 store_bool("has_drywet", (sp_wet!=NULL));
297 for (sp=controls.begin(); sp!=controls.end(); sp++) {
298 store_float_sp("param", (*sp)->get_value(), (*(*sp)));
301 store_bool("panel_hidden", panel->is_hidden());
303 indent[strlen(indent)-1]=0;
304 tX_store("%s</ladspa_plugin>\n", indent);
307 void vtt_fx_ladspa :: load(xmlDocPtr doc, xmlNodePtr node) {
310 list <tX_seqpar_vttfx *> :: iterator sp=controls.begin();
314 for (xmlNodePtr cur=node->xmlChildrenNode; cur!=NULL; cur=cur->next) {
315 if (cur->type == XML_ELEMENT_NODE) {
319 restore_int("ladspa_id", dummy);
320 restore_bool("panel_hidden", hidden);
321 restore_bool("has_drywet", drywet);
322 if (drywet) add_drywet();
324 if ((!elementFound) && (xmlStrcmp(cur->name, (xmlChar *) "param")==0)) {
329 if (sp==controls.end()) {
330 tX_warning("found unexpected parameters for ladspa plugin [%i].", dummy);
332 restore_float_id("param", val, (*(*sp)), (*sp)->do_exec(val));
333 (*sp)->do_update_graphics();
339 tX_warning("unhandled ladspa_plugin element %s.", cur->name);
344 panel->hide(!hidden);
347 void vtt_fx_ladspa :: toggle_drywet() {
355 void vtt_fx_ladspa :: add_drywet() {
358 sp_wet=new tX_seqpar_vttfx_float();
359 sp_wet->set_mapping_parameters(1.0, 0, 0.01, 1);
360 sprintf(buffer, "%s: Dry/Wet", plugin->getLabel());
361 sp_wet->set_name(buffer, "Dry/Wet");
362 sp_wet->set_vtt(vtt);
363 panel->add_client_widget(sp_wet->get_widget());
365 pthread_mutex_lock(&vtt_class::render_lock);
366 controls.push_back(sp_wet);
369 pthread_mutex_unlock(&vtt_class::render_lock);
372 void vtt_fx_ladspa :: remove_drywet() {
373 pthread_mutex_lock(&vtt_class::render_lock);
376 controls.remove(sp_wet);
381 pthread_mutex_unlock(&vtt_class::render_lock);
384 tX_drywet_type vtt_fx_ladspa::has_drywet_feature()
386 if (sp_wet) return DRYWET_ACTIVE;
387 else return DRYWET_AVAILABLE;
390 /****** STEREO plugins **********/
392 vtt_fx_stereo_ladspa::vtt_fx_stereo_ladspa(LADSPA_Stereo_Plugin *p, void *v):vtt_fx_ladspa(p,v)
394 input_port=input2_port=-1;
395 output_port=output2_port=-1;
398 for (int port=0; port < plugin->getPortCount(); port++) {
399 if (LADSPA_IS_PORT_AUDIO(cpd)) {
400 if (LADSPA_IS_PORT_INPUT(cpd)) {
401 if (input_port<0) { input_port=port; }
402 else if (input2_port<0) { input2_port=port; }
403 else { tX_error("Extra input port for plugin %s?", plugin->getName()); }
404 } else if (LADSPA_IS_PORT_OUTPUT(cpd)) {
405 if (output_port<0) { output_port=port; }
406 else if (output2_port<0) { output2_port=port; }
407 else { tX_error("Extra output port for plugin %s?", plugin->getName()); }
413 void vtt_fx_stereo_ladspa :: reconnect_buffer()
415 plugin->getDescriptor()->connect_port(instance, input_port, myvtt->output_buffer);
416 plugin->getDescriptor()->connect_port(instance, input2_port, myvtt->output_buffer2);
419 plugin->getDescriptor()->connect_port(instance, output_port, wet_buffer);
420 plugin->getDescriptor()->connect_port(instance, output2_port, wet_buffer2);
422 plugin->getDescriptor()->connect_port(instance, output_port, myvtt->output_buffer);
423 plugin->getDescriptor()->connect_port(instance, output2_port, myvtt->output_buffer2);
427 void vtt_fx_stereo_ladspa :: realloc_drywet()
430 wet_buffer=(f_prec *) malloc(sizeof(float)*vtt_class::samples_in_mix_buffer);
431 wet_buffer2=(f_prec *) malloc(sizeof(float)*vtt_class::samples_in_mix_buffer);
434 void vtt_fx_stereo_ladspa :: free_drywet()
446 void vtt_fx_stereo_ladspa :: run()
448 plugin->getDescriptor()->run(instance, (vtt_class::samples_in_mix_buffer)>>1);
451 f_prec wet=sp_wet->get_value();
454 for (unsigned int sample=0; sample < (vtt_class::samples_in_mix_buffer)>>1; sample++) {
455 myvtt->output_buffer[sample]=dry*myvtt->output_buffer[sample]+wet*wet_buffer[sample];
456 myvtt->output_buffer2[sample]=dry*myvtt->output_buffer2[sample]+wet*wet_buffer2[sample];
461 vtt_fx_stereo_ladspa :: ~vtt_fx_stereo_ladspa()
463 // rest should be handeld in parent's destrucutor.
464 if (wet_buffer2) free(wet_buffer2);
467 bool vtt_fx_stereo_ladspa::is_stereo() { return true; }