This is not a GNU-style ChangeLog but you sort of get the idea what was
changed.
+[v3.82] (pre-release)
+- applied a fix from Juha Erkkila <erkkila@cc.jyu.fi> that makes tX work on
+ systems that don't have procfs mounted.
+- added an optional Dry/Wet control for all LADSPA plugins. Simply click on the
+ plugin's label to add or remove the additional control.
+
[v3.81]
- JACK doesn't seem to like SCHED_FIFO clients so I added a little test that
will set SCHED_OTHER when jack output was selected. This will work for true
#define tX_error(fmt, args...); { fprintf(stderr, "* tX_error: "); fprintf(stderr, fmt , ## args); fprintf(stderr, "\n"); }
#define tX_warning(fmt, args...); { fprintf(stderr, "+ tX_warning: "); fprintf(stderr, fmt , ## args); fprintf(stderr, "\n"); }
+#ifdef MEM_DEBUG
+#define tX_freemem(ptr, varname, comment); fprintf(stderr, "** free() [%s] at %08x. %s.\n", varname, ptr, comment); free(ptr);
+#define tX_malloc(ptr, varname, comment, size, type); fprintf(stderr, "**[1/2] malloc() [%s]. Size: %i. %s.\n", varname, size, comment); ptr=type malloc(size); fprintf(stderr, "**[2/2] malloc() [%s]. ptr: %08x.\n", varname, ptr);
+#else
+#define tX_freemem(ptr, varname, comment); free(ptr);
+#define tX_malloc(ptr, varname, comment, size, type); ptr=type malloc(size);
+#endif
+
typedef enum {
OSS =0,
ALSA = 1,
gtk_label_set_text(GTK_LABEL(used_mem), buffer);
}
}
+ fclose(procfs);
+ } else {
+ gtk_label_set_text(GTK_LABEL(used_mem), "");
}
- fclose(procfs);
sprintf(buffer, "%i", vtt_class::vtt_amount);
gtk_label_set_text(GTK_LABEL(no_of_vtts), buffer);
#include <config.h>
#endif
-#ifdef DEBUG
-#define tX_freemem(ptr, varname, comment); fprintf(stderr, "** free() [%s] at %08x. %s.\n", varname, ptr, comment); free(ptr);
-#define tX_malloc(ptr, varname, comment, size, type); fprintf(stderr, "**[1/2] malloc() [%s]. Size: %i. %s.\n", varname, size, comment); ptr=type malloc(size); fprintf(stderr, "**[2/2] malloc() [%s]. ptr: %08x.\n", varname, ptr);
-#else
-#define tX_freemem(ptr, varname, comment); free(ptr);
-#define tX_malloc(ptr, varname, comment, size, type); ptr=type malloc(size);
-#endif
-
#include "tX_loaddlg.h"
#define USE_PREFETCH 1
void vtt_class :: ec_clear_buffer()
{
- f_prec *ptr;
+/* f_prec *ptr;
for (ptr=ec_buffer; ptr<=ec_delay; ptr++) {
*ptr=0.0;
- }
- ec_ptr=ec_buffer;
+ } */
+
+ memset(ec_buffer, 0, sizeof(ec_buffer));
+ ec_ptr=ec_buffer;
}
void vtt_class :: render()
}
vtt_fx :: ~vtt_fx() {}
+void vtt_fx::toggle_drywet() {}
+tX_drywet_type vtt_fx::has_drywet_feature() { return NOT_DRYWET_CAPABLE; }
/******************* builtin fx ***/
tX_store("%s<cutoff/>\n", indent);
}
+
const char *vtt_fx_lp :: get_info_string()
{
return "TerminatorX built-in resonant lowpass filter.";
return "TerminatorX built-in echo effect.";
}
-
/******************** LADSPA fx ***/
/* short cut "cpd" macro to current port descriptor */
void vtt_fx_ladspa :: reconnect_buffer()
{
- plugin->getDescriptor()->connect_port(instance, input_port, myvtt->output_buffer);
- plugin->getDescriptor()->connect_port(instance, output_port, myvtt->output_buffer);
+ plugin->getDescriptor()->connect_port(instance, input_port, myvtt->output_buffer);
+ if (wet_buffer) {
+ plugin->getDescriptor()->connect_port(instance, output_port, wet_buffer);
+ } else {
+ plugin->getDescriptor()->connect_port(instance, output_port, myvtt->output_buffer);
+ }
}
static void wrapstr(char *str)
sp->set_vtt(vtt);
controls.push_back(sp);
- /* if (plugin->getDescriptor()->run_adding && plugin->getDescriptor()->set_run_adding_gain) {
- sp = sp_outgain = new tX_seqpar_vttfx_float();
- sp->set_mapping_parameters(3, 0, 0.01, 1);
- sprintf(buffer, "%s: Out Gain", plugin->getName());
- sp->set_name(buffer, "Out Gain");
- sp->set_vtt(vtt);
- controls.push_back(sp);
- } else {
- sp_outgain = NULL;
- } */
-
- sp_outgain=NULL;
+ sp_wet=NULL;
+ wet_buffer=NULL;
/* connecting ports */
for (port=0; port < plugin->getPortCount(); port++) {
reconnect_buffer();
}
+void vtt_fx_ladspa :: realloc_drywet()
+{
+ free_drywet();
+ wet_buffer=(f_prec *) malloc(sizeof(float)*vtt_class::samples_in_mix_buffer);
+}
+
+void vtt_fx_ladspa :: free_drywet()
+{
+ if (wet_buffer) {
+ free(wet_buffer);
+ wet_buffer=NULL;
+ }
+}
+
void vtt_fx_ladspa :: activate()
{
+ if (sp_wet) {
+ realloc_drywet();
+ }
+ reconnect_buffer(); // we always have to reconnect...
if (plugin->getDescriptor()->activate) plugin->getDescriptor()->activate(instance);
}
void vtt_fx_ladspa :: deactivate()
{
if (plugin->getDescriptor()->deactivate) plugin->getDescriptor()->deactivate(instance);
+
+ free_drywet();
}
void vtt_fx_ladspa :: run()
{
- if (sp_outgain) {
- plugin->getDescriptor()->set_run_adding_gain(instance, sp_outgain->get_value());
- plugin->getDescriptor()->run_adding(instance, (vtt_class :: samples_in_mix_buffer)>>1);
- } else {
- plugin->getDescriptor()->run(instance, (vtt_class :: samples_in_mix_buffer)>>1);
+ plugin->getDescriptor()->run(instance, (vtt_class::samples_in_mix_buffer)>>1);
+
+ if (wet_buffer) {
+ f_prec wet=sp_wet->get_value();
+ f_prec dry=1.0-wet;
+
+ for (int sample=0; sample < (vtt_class::samples_in_mix_buffer)>>1; sample++) {
+ myvtt->output_buffer[sample]=dry*myvtt->output_buffer[sample]+wet*wet_buffer[sample];
+ }
}
}
delete (*sp);
}
plugin->getDescriptor()->cleanup(instance);
+
+ if (wet_buffer) free(wet_buffer);
delete panel;
}
strcat (indent, "\t");
store_int("ladspa_id", ID);
+ store_bool("has_drywet", (sp_wet!=NULL));
for (sp=controls.begin(); sp!=controls.end(); sp++) {
store_float_sp("param", (*sp)->get_value(), (*(*sp)));
list <tX_seqpar_vttfx *> :: iterator sp=controls.begin();
int elementFound;
double val;
+ bool bdummy;
for (xmlNodePtr cur=node->xmlChildrenNode; cur!=NULL; cur=cur->next) {
if (cur->type == XML_ELEMENT_NODE) {
restore_int("ladspa_id", dummy);
restore_bool("panel_hidden", hidden);
+ restore_bool_ac("has_drywet", bdummy, add_drywet());
if ((!elementFound) && (xmlStrcmp(cur->name, (xmlChar *) "param")==0)) {
val=0;
panel->hide(hidden);
}
+
+void vtt_fx_ladspa :: toggle_drywet() {
+ if (sp_wet) {
+ remove_drywet();
+ } else {
+ add_drywet();
+ }
+}
+
+void vtt_fx_ladspa :: add_drywet() {
+ char buffer[1024];
+
+ sp_wet=new tX_seqpar_vttfx_float();
+ sp_wet->set_mapping_parameters(1.0, 0, 0.01, 1);
+ sprintf(buffer, "%s: Dry/Wet", plugin->getLabel());
+ sp_wet->set_name(buffer, "Dry/Wet");
+ sp_wet->set_vtt(vtt);
+ panel->add_client_widget(sp_wet->get_widget());
+
+ pthread_mutex_lock(&vtt_class::render_lock);
+ controls.push_back(sp_wet);
+ deactivate();
+ activate();
+ pthread_mutex_unlock(&vtt_class::render_lock);
+}
+
+void vtt_fx_ladspa :: remove_drywet() {
+ pthread_mutex_lock(&vtt_class::render_lock);
+ deactivate();
+
+ controls.remove(sp_wet);
+ delete sp_wet;
+ sp_wet=NULL;
+
+ activate();
+ pthread_mutex_unlock(&vtt_class::render_lock);
+}
+
+tX_drywet_type vtt_fx_ladspa::has_drywet_feature()
+{
+ if (sp_wet) return DRYWET_ACTIVE;
+ else return DRYWET_AVAILABLE;
+}
/* abstract super class vtt_fx */
+typedef enum {
+ NOT_DRYWET_CAPABLE,
+ DRYWET_AVAILABLE,
+ DRYWET_ACTIVE
+} tX_drywet_type;
+
class vtt_fx
{
protected:
virtual void run()=NULL;
virtual int isEnabled()=NULL;
virtual void reconnect_buffer();
+ virtual void toggle_drywet();
+ virtual tX_drywet_type has_drywet_feature();
virtual const char *get_info_string()=NULL;
list <tX_seqpar_vttfx *> controls;
private:
tX_seqpar_vttfx *sp_enable;
- tX_seqpar_vttfx *sp_outgain;
+ tX_seqpar_vttfx *sp_wet;
+ f_prec *wet_buffer;
int input_port, output_port;
LADSPA_Handle *instance;
LADSPA_Plugin *plugin;
virtual void run();
virtual int isEnabled();
virtual void reconnect_buffer();
- virtual const char *get_info_string();
+ virtual const char *get_info_string();
+ void realloc_drywet();
+ void free_drywet();
+ virtual void toggle_drywet();
+ void add_drywet();
+ void remove_drywet();
+ virtual tX_drywet_type has_drywet_feature();
+
virtual void save(FILE *rc, gzFile rz, char *indent);
#ifdef ENABLE_TX_LEGACY
virtual void load(FILE *);
G_CALLBACK(drop_file), (void *) vtt);
}
-
+
+void vg_show_fx_menu(GtkWidget *, vtt_fx *effect);
+
void build_vtt_gui(vtt_class *vtt)
{
GtkWidget *tempbox;
/* Lowpass Panel */
p=new tX_panel("Lowpass", g->control_subbox);
+ g_signal_connect(G_OBJECT(p->get_labelbutton()), "clicked", G_CALLBACK(vg_show_fx_menu), vtt->lp_fx);
g->lp_panel=p;
g->lp_enable=gtk_check_button_new_with_label("Enable");
/* Echo Panel */
p=new tX_panel("Echo", g->control_subbox);
+ g_signal_connect(G_OBJECT(p->get_labelbutton()), "clicked", G_CALLBACK(vg_show_fx_menu), vtt->ec_fx);
g->ec_panel=p;
p->add_client_widget(vg_create_fx_bar(vtt, vtt->ec_fx, 0));
tx_l_note(effect->get_info_string());
}
+void vg_toggle_drywet(GtkWidget *wid, vtt_fx *effect)
+{
+ effect->toggle_drywet();
+}
+
+void vg_show_fx_menu(GtkWidget *wid, vtt_fx *effect)
+{
+ GtkWidget *menu=gtk_menu_new();
+ GtkWidget *item=gtk_menu_item_new_with_label("Show Info");
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+ gtk_widget_set_sensitive(item, (effect->has_drywet_feature()!=NOT_DRYWET_CAPABLE));
+ gtk_widget_show(item);
+ g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(vg_show_fx_info), effect);
+
+ switch (effect->has_drywet_feature()) {
+ case (NOT_DRYWET_CAPABLE):
+ item=gtk_menu_item_new_with_label("Add Dry/Wet Control");
+ gtk_widget_set_sensitive(item, FALSE);
+ break;
+ case (DRYWET_ACTIVE):
+ item=gtk_menu_item_new_with_label("Remove Dry/Wet Control");
+ break;
+ case (DRYWET_AVAILABLE):
+ item=gtk_menu_item_new_with_label("Add Dry/Wet Control");
+ break;
+ }
+
+ g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(vg_toggle_drywet), effect);
+
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+ gtk_widget_show(item);
+
+ gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, 0);
+
+ /* gtk+ is really waiting for this.. */
+ g_signal_emit_by_name(G_OBJECT(wid), "released", effect);
+}
+
void vg_create_fx_gui(vtt_class *vtt, vtt_fx_ladspa *effect, LADSPA_Plugin *plugin)
{
char buffer[1024];
p->add_client_widget((*sp)->get_widget());
}
- g_signal_connect(G_OBJECT(p->get_labelbutton()), "clicked", (GtkSignalFunc) vg_show_fx_info, (void *) effect);
- gui_set_tooltip(p->get_labelbutton(), "Click here to learn more about this plugin.");
+ g_signal_connect(G_OBJECT(p->get_labelbutton()), "clicked", (GtkSignalFunc) vg_show_fx_menu, (void *) effect);
+ gui_set_tooltip(p->get_labelbutton(), "Click here for menu");
effect->set_panel_widget(p->get_widget());
effect->set_panel(p);