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.
+- added an additional stereo effects queue that allows loading stereo LADPSA
+ plugins. The stereo effects are located below the mono effects - to add a new
+ instance press the "Stereo FX" button and select the plugin of your choice.
+- fixed the plugin menu - empty categories no longer get a menu entry.
+- plugins that do not qualify as realtime capable will now be disabled.
[v3.81]
- JACK doesn't seem to like SCHED_FIFO clients so I added a little test that
dnl Process this file with autoconf to produce a configure script.
AC_INIT(src/tX_global.h)
-AM_INIT_AUTOMAKE(terminatorX, 3.81)
+AM_INIT_AUTOMAKE(terminatorX, 3.82)
AM_CONFIG_HEADER(config.h)
AC_ARG_ENABLE(sox, [ --enable-sox use sox as input converter. (default=auto) ])
LADSPA_Class::init();
LADSPA_Plugin::init();
+ //LADSPA_Class::dump();
#ifdef USE_JACK
tX_jack_client::init();
#endif
#include <string.h>
std::list <LADSPA_Plugin *> LADSPA_Plugin :: plugin_list;
+std::list <LADSPA_Stereo_Plugin *> LADSPA_Stereo_Plugin :: stereo_plugin_list;
void LADSPA_Plugin :: init ()
{
for (i=0; (descriptor = desc_func(i)) != NULL; i++) {
if (LADSPA_IS_INPLACE_BROKEN(descriptor->Properties)) {
tX_warning("Plugin \"%s\" disabled. No in-place processing support.", descriptor->Name);
+ } else if (!LADSPA_IS_HARD_RT_CAPABLE(descriptor->Properties)) {
+ tX_warning("Plugin \"%s\" disabled. Not realtime capable.", descriptor->Name);
} else {
in_audio=0; out_audio=0; in_ctrl=0;
if ((in_audio == 1) && (out_audio == 1)) {
new LADSPA_Plugin(descriptor, filename);
+ } if ((in_audio == 2) && (out_audio == 2)) {
+ new LADSPA_Stereo_Plugin(descriptor, filename);
}
- else { tX_warning("Plugin \"%s\" disabled. Not a 1-in/1-out plugin.", descriptor->Name); }
+ else { tX_warning("Plugin \"%s\" disabled. Neither mono nor stereo.", descriptor->Name); }
}
}
}
return NULL;
}
+
+/* STEREO */
+
+LADSPA_Stereo_Plugin :: LADSPA_Stereo_Plugin (const LADSPA_Descriptor *ld, char *filename)
+{
+ ladspa_descriptor = ld;
+
+ stereo_plugin_list.push_back(this);
+ strcpy(file, filename);
+ sprintf(info_string, "LADSPA-Stereo-Plugin: %s\nLabel: %s\nFile: %s\nUnique ID: %li\nMaker: %s\nCopyright: %s", ld->Name, ld->Label, file, ld->UniqueID, ld->Maker, ld->Copyright);
+ LADSPA_Class::add_stereo_plugin(this);
+}
+
+LADSPA_Stereo_Plugin * LADSPA_Stereo_Plugin :: getPluginByIndex(int i)
+{
+ std::list <LADSPA_Stereo_Plugin *> :: iterator plugin;
+ int p;
+
+ plugin = stereo_plugin_list.begin();
+ for (p=0; (p<i) && (plugin != stereo_plugin_list.end()); p++, plugin++);
+
+ if (plugin==stereo_plugin_list.end()) return NULL;
+
+ else return (*plugin);
+}
+
+LADSPA_Stereo_Plugin * LADSPA_Stereo_Plugin :: getPluginByUniqueID(long ID)
+{
+ std::list <LADSPA_Stereo_Plugin *> :: iterator plugin;
+
+ for (plugin=stereo_plugin_list.begin(); plugin != stereo_plugin_list.end(); plugin++) {
+ if ((*plugin)->getUniqueID()==ID) return (*plugin);
+ }
+
+ return NULL;
+}
+
+bool LADSPA_Stereo_Plugin::is_stereo() { return true; }
+bool LADSPA_Plugin::is_stereo() { return false; }
class LADSPA_Plugin
{
- private:
+ protected:
const LADSPA_Descriptor *ladspa_descriptor;
LADSPA_Plugin(const LADSPA_Descriptor *ld, char *filename);
+ LADSPA_Plugin() {}
char info_string[4096];
char file[1024];
+ private:
static list <LADSPA_Plugin *> plugin_list;
static void scandir(char *dir);
static void handlelib(void *lib, LADSPA_Descriptor_Function desc_func, char* filename);
static void init();
static void status();
static void debug_display();
+ virtual bool is_stereo();
char *get_info_string() { return info_string; }
char *get_file_name() { return file; }
const LADSPA_Descriptor *getDescriptor() { return ladspa_descriptor; }
};
+class LADSPA_Stereo_Plugin : public LADSPA_Plugin
+{
+ private:
+ static list <LADSPA_Stereo_Plugin *> stereo_plugin_list;
+
+ public:
+ LADSPA_Stereo_Plugin(const LADSPA_Descriptor *ld, char *filename);
+
+ public:
+ virtual bool is_stereo();
+ static LADSPA_Stereo_Plugin * getPluginByIndex(int i);
+ static LADSPA_Stereo_Plugin * getPluginByUniqueID(long ID);
+};
+
#endif
}
bool LADSPA_Class :: add_plugin(LADSPA_Plugin *plugin) {
- return root->add_plugin_instance(plugin);
+ return root->add_plugin_instance(plugin, MONO);
}
-bool LADSPA_Class :: add_plugin_instance(LADSPA_Plugin *plugin) {
+bool LADSPA_Class :: add_stereo_plugin(LADSPA_Stereo_Plugin *plugin) {
+ return root->add_plugin_instance(plugin, STEREO);
+}
+
+bool LADSPA_Class :: add_plugin_instance(LADSPA_Plugin *plugin, LADSPA_Plugin_Type type) {
if (accept_all) {
- insert_plugin(plugin);
+ insert_plugin(plugin, type);
return true;
}
for (i=registered_ids.begin(); i!=registered_ids.end(); i++) {
if ((*i)==id) {
/* The plugin belongs to this class... */
- insert_plugin(plugin);
+ insert_plugin(plugin, type);
return true;
}
}
for (cls=subclasses.begin(); cls!=subclasses.end(); cls++) {
LADSPA_Class *lrdf_class=(*cls);
- if (lrdf_class->add_plugin_instance(plugin)) return true;
+ if (lrdf_class->add_plugin_instance(plugin, type)) return true;
}
/* Giving up... */
return false;
}
-void LADSPA_Class::insert_plugin(LADSPA_Plugin *plugin) {
+void LADSPA_Class::insert_plugin(LADSPA_Plugin *plugin, LADSPA_Plugin_Type type) {
std::list <LADSPA_Plugin *> :: iterator i;
+ std::list <LADSPA_Plugin *> *list;
- for (i=plugins.begin(); i!=plugins.end(); i++) {
+ if (type==MONO) {
+ list=&plugins;
+ } else {
+ list=(std::list <LADSPA_Plugin *> *) &stereo_plugins;
+ }
+
+ for (i=list->begin(); i!=list->end(); i++) {
LADSPA_Plugin *a_plug=(*i);
int res=compare(plugin->getName(), a_plug->getName());
if (res < 2) {
- plugins.insert(i, plugin);
+ list->insert(i, plugin);
return;
}
}
- plugins.push_back(plugin);
+ list->push_back(plugin);
}
void LADSPA_Class::list(char *buffer) {
printf("%s - plugin: %s\n", buffer, (*i)->getName());
}
+ std::list <LADSPA_Stereo_Plugin *> :: iterator s;
+ for (s=stereo_plugins.begin(); s!=stereo_plugins.end(); s++) {
+ printf("%s - stereo plugin: %s\n", buffer, (*s)->getName());
+ }
+
std::list <LADSPA_Class *> :: iterator c;
for (c=subclasses.begin(); c!=subclasses.end(); c++) (*c)->list(buffer);
}
}
+static void stereo_menu_callback(GtkWidget *wid, LADSPA_Stereo_Plugin *plugin) {
+ vtt_class *vtt=LADSPA_Class::get_current_vtt();
+
+ if (vtt) {
+ vtt->add_stereo_effect(plugin);
+ } else {
+ tX_error("LADSPA_Class::menu_callback() no vtt");
+ }
+}
-GtkWidget * LADSPA_Class :: get_menu() {
+int LADSPA_Class :: plugins_in_class(LADSPA_Plugin_Type type) {
+ std::list <LADSPA_Class *> :: iterator cls;
+ std::list <LADSPA_Plugin *> *list;
+ int counter=0;
+
+ if (type==MONO) {
+ list=&plugins;
+ } else {
+ list=(std::list <LADSPA_Plugin *> *) &stereo_plugins;
+ }
+ counter=list->size();
+
+ for (cls=subclasses.begin(); cls!=subclasses.end(); cls++) {
+ counter+=(*cls)->plugins_in_class(type);
+ }
+
+ return counter;
+}
+
+GtkWidget * LADSPA_Class :: get_menu(LADSPA_Plugin_Type type) {
std::list <LADSPA_Class *> :: iterator cls;
GtkWidget *menu=gtk_menu_new();
GtkWidget *item;
+ bool need_separator=false;
for (cls=subclasses.begin(); cls!=subclasses.end(); cls++) {
LADSPA_Class *c=(*cls);
- if (c->plugins.size() || c->subclasses.size()) {
+ if (c->plugins_in_class(type)>0) {
item=gtk_menu_item_new_with_label(c->label);
- GtkWidget *submenu=c->get_menu();
+ GtkWidget *submenu=c->get_menu(type);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
gtk_widget_show(item);
+ need_separator=true;
}
}
- if (subclasses.size() && plugins.size()) {
+ std::list <LADSPA_Plugin *> *list;
+
+ if (type==MONO) {
+ list=&plugins;
+ } else {
+ list=(std::list <LADSPA_Plugin *> *) &stereo_plugins;
+ }
+
+ if (need_separator && list->size()) {
item = gtk_menu_item_new();
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
gtk_widget_set_sensitive (item, FALSE);
std::list <LADSPA_Plugin *> :: iterator plugin;
- for (plugin=plugins.begin(); plugin != plugins.end(); plugin++) {
+ for (plugin=list->begin(); plugin!=list->end(); plugin++) {
char buffer[512];
LADSPA_Plugin *p=(*plugin);
sprintf(buffer, "%s - (%s, %li)", p->getName(), p->getLabel(), p->getUniqueID());
item=gtk_menu_item_new_with_label(buffer);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
- g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(menu_callback), p);
+ g_signal_connect(G_OBJECT(item), "activate", (type == MONO) ? G_CALLBACK(menu_callback) : G_CALLBACK(stereo_menu_callback), p);
gtk_widget_show(item);
}
}
GtkWidget * LADSPA_Class :: get_ladspa_menu() {
- return root->get_menu();
+ return root->get_menu(MONO);
+}
+
+GtkWidget * LADSPA_Class :: get_stereo_ladspa_menu() {
+ return root->get_menu(STEREO);
}
#include <gtk/gtk.h>
#include "tX_vtt.h"
+typedef enum {
+ MONO,
+ STEREO
+} LADSPA_Plugin_Type;
+
class LADSPA_Class { // Yeah, I know "class" name for C++ class - but it just seems to fit best...
protected:
static LADSPA_Class *root;
static LADSPA_Class *unclassified;
+
static std::list <char *> rdf_files;
static vtt_class *current_vtt;
static bool liblrdf_error;
std::list <LADSPA_Class *> subclasses;
std::list <long> registered_ids;
std::list <LADSPA_Plugin *> plugins;
+ std::list <LADSPA_Stereo_Plugin *> stereo_plugins;
static void scandir(char *dir);
- bool add_plugin_instance(LADSPA_Plugin *);
+ bool add_plugin_instance(LADSPA_Plugin *, LADSPA_Plugin_Type);
void insert_class(LADSPA_Class *);
- void insert_plugin(LADSPA_Plugin *);
+ void insert_plugin(LADSPA_Plugin *, LADSPA_Plugin_Type);
+ int plugins_in_class(LADSPA_Plugin_Type type);
void list(char *);
- GtkWidget *get_menu();
+ GtkWidget *get_menu(LADSPA_Plugin_Type);
public:
LADSPA_Class(char *uri);
LADSPA_Class(); // For the unclassified class;
static bool add_plugin(LADSPA_Plugin *plugin);
+ static bool add_stereo_plugin(LADSPA_Stereo_Plugin *plugin);
+
static void init();
static void dump();
static GtkWidget *get_ladspa_menu();
+ static GtkWidget *get_stereo_ladspa_menu();
static void set_current_vtt(vtt_class *vtt) { current_vtt=vtt; }
static vtt_class *get_current_vtt() { return current_vtt; }
};
ec_length=1;
ec_output_buffer=NULL;
output_buffer=NULL;
+ output_buffer2=NULL;
set_volume(1);
set_pitch(1);
if (audiofile) delete audiofile;
//if (buffer) free(buffer);
if (output_buffer) tX_freemem(output_buffer, "output_buffer", "vtt Destructor");
+ if (output_buffer2) tX_freemem(output_buffer2, "output_buffer2", "vtt Destructor");
+
vtt_amount--;
if (mix_solo) solo_ctr--;
if (output_buffer) tX_freemem(output_buffer, "output_buffer", "vtt set_output_buffer_size()");
tX_malloc(output_buffer, "output_buffer", "vtt set_output_buffer_size()", sizeof(float)*newsize, (float *));
+ if (output_buffer2) tX_freemem(output_buffer2, "output_buffer2", "vtt set_output_buffer2_size()");
+ tX_malloc(output_buffer2, "output_buffer2", "vtt set_output_buffer2_size()", sizeof(float)*newsize, (float *));
end_of_outputbuffer = output_buffer + newsize; //size_t(sizeof(float)*(newsize));
(*effect)->reconnect_buffer();
}
- if (output_buffer) return(0);
- else return(0);
+ return 0;
}
void vtt_class :: set_volume(f_prec newvol)
void vtt_class :: render()
{
list <vtt_fx *> :: iterator effect;
-
+
if (do_scratch) {
if (sense_cycles>0) {
sense_cycles--;
for (effect=fx_list.begin(); effect != fx_list.end(); effect++) {
if ((*effect)->isEnabled()) (*effect)->run();
}
+
+ if (stereo_fx_list.size()>0) {
+ // fill 2nd channel
+ memcpy((void *) output_buffer2, (void *) output_buffer, sizeof(float)*((int)samples_in_outputbuffer));
+
+ // apply stereo effects.
+ list <vtt_fx_stereo_ladspa *> :: iterator stereo_effect;
+
+ for (stereo_effect=stereo_fx_list.begin(); stereo_effect != stereo_fx_list.end(); stereo_effect++) {
+ if ((*stereo_effect)->isEnabled()) (*stereo_effect)->run();
+ }
+
+ for (int sample=0; sample<samples_in_outputbuffer; sample++) {
+ f_prec temp=output_buffer[sample]*=res_volume_left;
+ output_buffer2[sample]*=res_volume_right;
+
+ temp=fabs(temp);
+ if (temp>max_value) max_value=temp;
+ }
+ } else {
+ for (int sample=0; sample<samples_in_outputbuffer; sample++) {
+ output_buffer2[sample]=output_buffer[sample]*res_volume_right;
+ f_prec temp=output_buffer[sample]*=res_volume_left;
+
+ temp=fabs(temp);
+ if (temp>max_value) max_value=temp;
+ }
+ }
+
+ if (ec_enable) {
+ for (int sample=0; sample<samples_in_outputbuffer; sample++) {
+ f_prec temp=ec_output_buffer[sample];
+ output_buffer[sample]+=temp*ec_volume_left;
+ output_buffer2[sample]+=temp*ec_volume_right;
+ }
+ }
}
extern void vg_create_fx_gui(vtt_class *vtt, vtt_fx_ladspa *effect, LADSPA_Plugin *plugin);
return new_effect;
}
+vtt_fx_stereo_ladspa * vtt_class :: add_stereo_effect (LADSPA_Stereo_Plugin *plugin)
+{
+ vtt_fx_stereo_ladspa *new_effect;
+
+ new_effect = new vtt_fx_stereo_ladspa(plugin, this);
+ pthread_mutex_lock(&render_lock);
+ stereo_fx_list.push_back(new_effect);
+ if (is_playing) new_effect->activate();
+ pthread_mutex_unlock(&render_lock);
+ vg_create_fx_gui(this, new_effect, plugin);
+
+ return new_effect;
+}
+
void vtt_class :: calc_speed()
{
do_mute=0;
} else {
vtt=render_list.begin();
(*vtt)->render();
- max=(*vtt)->max_value;
- min=max;
-
- for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++) {
- temp=(*vtt)->output_buffer[sample];
- mix_buffer[mix_sample]=temp*(*vtt)->res_volume_left;
- mix_sample++;
- mix_buffer[mix_sample]=temp*(*vtt)->res_volume_right;
- mix_sample++;
-
- if (temp>max) max=temp;
- else if (temp<min) min=temp;
- }
- min*=-1.0;
- if (min>max) (*vtt)->max_value=min; else (*vtt)->max_value=max;
-
- if ((*vtt)->ec_enable) {
- for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++) {
- temp=(*vtt)->ec_output_buffer[sample];
-
- mix_buffer[mix_sample]+=temp*(*vtt)->ec_volume_left;
- mix_sample++;
- mix_buffer[mix_sample]+=temp*(*vtt)->ec_volume_right;
- mix_sample++;
- }
+ for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++) {
+ mix_buffer[mix_sample++]=(*vtt)->output_buffer[sample];
+ mix_buffer[mix_sample++]=(*vtt)->output_buffer2[sample];
}
-
+
if (master_triggered) {
for (vtt=main_list.begin(); vtt!=main_list.end(); vtt++) {
if ((*vtt)->is_sync_client) {
}
vtt=render_list.begin();
+
for (vtt++; vtt!=render_list.end(); vtt++) {
(*vtt)->render();
- max=(*vtt)->max_value;
- min=max;
for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++) {
- temp=(*vtt)->output_buffer[sample];
- mix_buffer[mix_sample]+=temp*(*vtt)->res_volume_left;
- mix_sample++;
- mix_buffer[mix_sample]+=temp*(*vtt)->res_volume_right;
- mix_sample++;
-
- if (temp>max) max=temp;
- else if (temp<min) min=temp;
- }
-
- min*=-1.0;
- if (min>max) (*vtt)->max_value=min; else (*vtt)->max_value=max;
-
- if ((*vtt)->ec_enable) {
- for (sample=0, mix_sample=0; sample<(*vtt)->samples_in_outputbuffer; sample++) {
- temp=(*vtt)->ec_output_buffer[sample];
-
- mix_buffer[mix_sample]+=temp*(*vtt)->ec_volume_left;
- mix_sample++;
- mix_buffer[mix_sample]+=temp*(*vtt)->ec_volume_right;
- mix_sample++;
- }
+ mix_buffer[mix_sample++]+=(*vtt)->output_buffer[sample];
+ mix_buffer[mix_sample++]+=(*vtt)->output_buffer2[sample];
}
}
int vtt_class :: trigger(bool need_lock)
{
- list <vtt_fx *> :: iterator effect;
-
if (!buffer) return 1;
retrigger();
cleanup_required=false;
/* activating plugins */
- for (effect=fx_list.begin(); effect != fx_list.end(); effect++) {
+ for (list <vtt_fx *> :: iterator effect=fx_list.begin(); effect != fx_list.end(); effect++) {
+ (*effect)->activate();
+ }
+
+ for (list <vtt_fx_stereo_ladspa *> :: iterator effect=stereo_fx_list.begin(); effect != stereo_fx_list.end(); effect++) {
(*effect)->activate();
}
#define store(data); if (fwrite((void *) &data, sizeof(data), 1, output)!=1) res+=1;
int vtt_class :: save(FILE *rc, gzFile rz, char *indent) {
- list <vtt_fx *> :: iterator effect;
char tmp_xml_buffer[4096];
int res=0;
tX_store("%s<fx>\n", indent);
strcat(indent, "\t");
- for (effect=fx_list.begin(); effect!=fx_list.end(); effect++) {
+ for (list <vtt_fx *> :: iterator effect=fx_list.begin(); effect!=fx_list.end(); effect++) {
(*effect)->save(rc, rz, indent);
}
indent[strlen(indent)-1]=0;
tX_store("%s</fx>\n", indent);
+ tX_store("%s<stereo_fx>\n", indent);
+ strcat(indent, "\t");
+
+ for (list <vtt_fx_stereo_ladspa *> :: iterator effect=stereo_fx_list.begin(); effect!=stereo_fx_list.end(); effect++) {
+ (*effect)->save(rc, rz, indent);
+ }
+ indent[strlen(indent)-1]=0;
+ tX_store("%s</stereo_fx>\n", indent);
+
indent[strlen(indent)-1]=0;
tX_store("%s</turntable>\n", indent);
restore_float_ac("audio_x_zoom", tmp, gui_set_audio_x_zoom(this,tmp));
vg_adjust_zoom(gui.zoom, this);
- if (xmlStrcmp(cur->name, (xmlChar *) "fx")==0) {
+ if ((xmlStrcmp(cur->name, (xmlChar *) "fx")==0) ||
+ (xmlStrcmp(cur->name, (xmlChar *) "stereo_fx")==0)) {
+ bool stereo=(xmlStrcmp(cur->name, (xmlChar *) "stereo_fx")==0);
xmlNodePtr fx=cur;
elementFound=1;
if (ladspa_id!=-1) {
LADSPA_Plugin *plugin=LADSPA_Plugin::getPluginByUniqueID(ladspa_id);
+ if (!plugin) plugin=LADSPA_Stereo_Plugin::getPluginByUniqueID(ladspa_id);
+
if (plugin) {
- vtt_fx_ladspa *ladspa_effect=add_effect(plugin);
+ vtt_fx_ladspa *ladspa_effect=NULL;
+
+ if (plugin->is_stereo()) {
+ ladspa_effect=add_stereo_effect((LADSPA_Stereo_Plugin *) plugin);
+ if (!stereo) {
+ sprintf(buffer,"Trying to load mono plugin into stereo queue [%i].", ladspa_id);
+ tx_note(buffer, true);
+ }
+ } else {
+ ladspa_effect=add_effect(plugin);
+ if (stereo) {
+ sprintf(buffer,"Trying to load stereo plugin into mono queue [%i].", ladspa_id);
+ tx_note(buffer, true);
+ }
+ }
+
ladspa_effect->load(doc, pluginNode);
} else {
sprintf(buffer,"The terminatorX set file you are loading makes use of a LADSPA plugin that is not installed on this machine. The plugin's ID is [%i].", ladspa_id);
if (fn) new_tt->load_file(fn);
}
-extern void vg_move_fx_panel_up(GtkWidget *wid, vtt_class *vtt);
-extern void vg_move_fx_panel_down(GtkWidget *wid, vtt_class *vtt);
+extern void vg_move_fx_panel_up(GtkWidget *wid, vtt_class *vtt, bool stereo);
+extern void vg_move_fx_panel_down(GtkWidget *wid, vtt_class *vtt, bool stereo);
-//#define debug_fx_stack(); for (i=fx_list.begin(); i != fx_list.end(); i++) puts((*i)->get_info_string());
+//#define debug_fx_stack(); for (i=list->begin(); i != list->end(); i++) puts((*i)->get_info_string());
#define debug_fx_stack();
void vtt_class :: effect_up(vtt_fx *effect)
{
list <vtt_fx *> :: iterator i;
list <vtt_fx *> :: iterator previous;
+ list <vtt_fx *> *list;
int ok=0;
+ if (effect->is_stereo()) {
+ list=(std::list <vtt_fx *> *) &stereo_fx_list;
+ } else {
+ list=&fx_list;
+ }
+
debug_fx_stack();
- if ((*fx_list.begin())==effect) return;
+ if ((*list->begin())==effect) return;
- for (previous=i=fx_list.begin(); i != fx_list.end(); i++) {
+ for (previous=i=list->begin(); i != list->end(); i++) {
if ((*i) == effect) {
ok=1;
break;
if (ok) {
pthread_mutex_lock(&render_lock);
- fx_list.remove(effect);
- fx_list.insert(previous, effect);
+ list->remove(effect);
+ list->insert(previous, effect);
pthread_mutex_unlock(&render_lock);
- vg_move_fx_panel_up(effect->get_panel_widget(), this);
+ vg_move_fx_panel_up(effect->get_panel_widget(), this, effect->is_stereo());
}
debug_fx_stack();
void vtt_class :: effect_down(vtt_fx *effect)
{
list <vtt_fx *> :: iterator i;
+ list <vtt_fx *> *list;
int ok=0;
+
+ if (effect->is_stereo()) {
+ list=(std::list <vtt_fx *> *) &stereo_fx_list;
+ } else {
+ list=&fx_list;
+ }
debug_fx_stack();
- for (i=fx_list.begin(); i != fx_list.end(); i++) {
+ for (i=list->begin(); i != list->end(); i++) {
if ((*i) == effect) {
ok=1;
break;
}
}
- if ((ok) && (i!=fx_list.end())) {
+ if ((ok) && (i!=list->end())) {
i++;
- if (i==fx_list.end()) return;
+ if (i==list->end()) return;
i++;
pthread_mutex_lock(&render_lock);
- fx_list.remove(effect);
+ list->remove(effect);
- fx_list.insert(i, effect);
- vg_move_fx_panel_down(effect->get_panel_widget(), this);
+ list->insert(i, effect);
+ vg_move_fx_panel_down(effect->get_panel_widget(), this, effect->is_stereo());
pthread_mutex_unlock(&render_lock);
}
void vtt_class :: effect_remove(vtt_fx_ladspa *effect)
{
pthread_mutex_lock(&render_lock);
- fx_list.remove(effect);
+ if (effect->is_stereo()) {
+ stereo_fx_list.remove((vtt_fx_stereo_ladspa *) effect);
+ } else {
+ fx_list.remove(effect);
+ }
pthread_mutex_unlock(&render_lock);
delete effect;
f_prec *output_buffer;
f_prec *end_of_outputbuffer;
+
+ f_prec *output_buffer2; // 2nd audio channel
+
f_prec samples_in_outputbuffer;
f_prec inv_samples_in_outputbuffer;
f_prec audiofile_pitch_correction;
list <vtt_fx *> fx_list;
+ list <vtt_fx_stereo_ladspa *> stereo_fx_list;
public:
/* Methods */
void xy_input(f_prec, f_prec);
vtt_fx_ladspa * add_effect(LADSPA_Plugin *);
+ vtt_fx_stereo_ladspa * add_stereo_effect (LADSPA_Stereo_Plugin *plugin);
void calc_speed();
void render();
vtt_fx :: ~vtt_fx() {}
void vtt_fx::toggle_drywet() {}
+bool vtt_fx::is_stereo() { return false; }
tX_drywet_type vtt_fx::has_drywet_feature() { return NOT_DRYWET_CAPABLE; }
/******************* builtin fx ***/
plugin->getDescriptor()->connect_port(instance, port, &ladspa_dummy_output_port);
}
}
- reconnect_buffer();
}
void vtt_fx_ladspa :: realloc_drywet()
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) {
+ bool drywet=false;
elementFound=0;
restore_int("ladspa_id", dummy);
restore_bool("panel_hidden", hidden);
- restore_bool_ac("has_drywet", bdummy, add_drywet());
+ restore_bool("has_drywet", drywet);
+ if (drywet) add_drywet();
if ((!elementFound) && (xmlStrcmp(cur->name, (xmlChar *) "param")==0)) {
val=0;
if (sp_wet) return DRYWET_ACTIVE;
else return DRYWET_AVAILABLE;
}
+
+/****** STEREO plugins **********/
+
+vtt_fx_stereo_ladspa::vtt_fx_stereo_ladspa(LADSPA_Stereo_Plugin *p, void *v):vtt_fx_ladspa(p,v)
+{
+ input_port=input2_port=-1;
+ output_port=output2_port=-1;
+ wet_buffer2=NULL;
+
+ for (int port=0; port < plugin->getPortCount(); port++) {
+ if (LADSPA_IS_PORT_AUDIO(cpd)) {
+ if (LADSPA_IS_PORT_INPUT(cpd)) {
+ if (input_port<0) { input_port=port; }
+ else if (input2_port<0) { input2_port=port; }
+ else { tX_error("Extra input port for plugin %s?", plugin->getName()); }
+ } else if (LADSPA_IS_PORT_OUTPUT(cpd)) {
+ if (output_port<0) { output_port=port; }
+ else if (output2_port<0) { output2_port=port; }
+ else { tX_error("Extra output port for plugin %s?", plugin->getName()); }
+ }
+ }
+ }
+};
+
+void vtt_fx_stereo_ladspa :: reconnect_buffer()
+{
+ plugin->getDescriptor()->connect_port(instance, input_port, myvtt->output_buffer);
+ plugin->getDescriptor()->connect_port(instance, input2_port, myvtt->output_buffer2);
+
+ if (wet_buffer) {
+ plugin->getDescriptor()->connect_port(instance, output_port, wet_buffer);
+ plugin->getDescriptor()->connect_port(instance, output2_port, wet_buffer2);
+ } else {
+ plugin->getDescriptor()->connect_port(instance, output_port, myvtt->output_buffer);
+ plugin->getDescriptor()->connect_port(instance, output2_port, myvtt->output_buffer2);
+ }
+}
+
+void vtt_fx_stereo_ladspa :: realloc_drywet()
+{
+ free_drywet();
+ wet_buffer=(f_prec *) malloc(sizeof(float)*vtt_class::samples_in_mix_buffer);
+ wet_buffer2=(f_prec *) malloc(sizeof(float)*vtt_class::samples_in_mix_buffer);
+}
+
+void vtt_fx_stereo_ladspa :: free_drywet()
+{
+ if (wet_buffer) {
+ free(wet_buffer);
+ wet_buffer=NULL;
+ }
+ if (wet_buffer2) {
+ free(wet_buffer2);
+ wet_buffer2=NULL;
+ }
+}
+
+void vtt_fx_stereo_ladspa :: run()
+{
+ 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];
+ myvtt->output_buffer2[sample]=dry*myvtt->output_buffer2[sample]+wet*wet_buffer2[sample];
+ }
+ }
+}
+
+vtt_fx_stereo_ladspa :: ~vtt_fx_stereo_ladspa()
+{
+ // rest should be handeld in parent's destrucutor.
+ if (wet_buffer2) free(wet_buffer2);
+}
+
+bool vtt_fx_stereo_ladspa::is_stereo() { return true; }
virtual int isEnabled()=NULL;
virtual void reconnect_buffer();
virtual void toggle_drywet();
+ virtual bool is_stereo();
virtual tX_drywet_type has_drywet_feature();
virtual const char *get_info_string()=NULL;
{
public:
list <tX_seqpar_vttfx *> controls;
- private:
+ protected:
tX_seqpar_vttfx *sp_enable;
tX_seqpar_vttfx *sp_wet;
f_prec *wet_buffer;
virtual int isEnabled();
virtual void reconnect_buffer();
virtual const char *get_info_string();
- void realloc_drywet();
- void free_drywet();
+ virtual void realloc_drywet();
+ virtual void free_drywet();
virtual void toggle_drywet();
void add_drywet();
void remove_drywet();
virtual void load(xmlDocPtr, xmlNodePtr);
};
+class vtt_fx_stereo_ladspa : public vtt_fx_ladspa {
+ private:
+ f_prec *wet_buffer2;
+ int input2_port, output2_port;
+
+ protected:
+ virtual void reconnect_buffer();
+ virtual void realloc_drywet();
+ virtual void free_drywet();
+
+ public:
+ vtt_fx_stereo_ladspa(LADSPA_Stereo_Plugin *, void *);
+ virtual bool is_stereo();
+ virtual void run();
+ virtual ~vtt_fx_stereo_ladspa();
+};
#endif
g_signal_emit_by_name(G_OBJECT(wid), "released", vtt);
}
+void stereo_fx_button_pressed(GtkWidget *wid, vtt_class *vtt)
+{
+ vtt_gui *g=&vtt->gui;
+
+ LADSPA_Class::set_current_vtt(vtt);
+
+ if (g->ladspa_menu) gtk_object_destroy(GTK_OBJECT(g->ladspa_menu));
+ g->ladspa_menu=LADSPA_Class::get_stereo_ladspa_menu();
+ gtk_menu_popup (GTK_MENU(g->ladspa_menu), NULL, NULL, NULL, NULL, 0, 0);
+
+ /* gtk+ is really waiting for this.. */
+ g_signal_emit_by_name(G_OBJECT(wid), "released", vtt);
+}
+
void gui_set_name(vtt_class *vtt, char *newname)
{
char bold_name[128];
connect_button(adjust_button, vg_adjust_pitch_vtt);
connect_adj(cycles, client_setup_number);
connect_press_button(fx_button, fx_button_pressed);
+ connect_press_button(stereo_fx_button, stereo_fx_button_pressed);
connect_button(lp_enable, lp_enabled);
connect_adj(lp_gain, lp_gain_changed);
g_signal_connect(G_OBJECT(dummy), "button_press_event", (GtkSignalFunc) tX_seqpar::tX_seqpar_press, &vtt->sp_sync_cycles);
gtk_box_pack_start(GTK_BOX(g->control_subbox), p->get_widget(), WID_FIX);
-
+
+ g->fx_box=gtk_vbox_new(FALSE,0);
+ gtk_box_pack_start(GTK_BOX(g->control_subbox), g->fx_box, WID_FIX);
+ gtk_widget_show(g->fx_box);
+
dummy=gtk_button_new_with_label("FX");
gtk_container_foreach(GTK_CONTAINER(dummy), (GtkCallback) tX_panel_make_label_bold, NULL);
gtk_widget_show(dummy);
g->fx_button=dummy;
gui_set_tooltip(g->fx_button, "Click here to load a LADSPA plugin. You will get a menu from which you can choose which plugin to load.");
- gtk_box_pack_start(GTK_BOX(g->control_subbox), dummy, WID_FIX);
+ gtk_box_pack_start(GTK_BOX(g->fx_box), dummy, WID_FIX);
/* 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);
+ p=new tX_panel("Lowpass", g->fx_box);
+ g_signal_connect(G_OBJECT(p->get_labelbutton()), "pressed", G_CALLBACK(vg_show_fx_menu), vtt->lp_fx);
g->lp_panel=p;
g->lp_enable=gtk_check_button_new_with_label("Enable");
p->add_client_widget(g->lp_resod->get_widget());
gui_set_tooltip(g->lp_resod->get_entry(), "Adjust the resonance of the lowpass filter. This value determines how much the signal at the cutoff frequency will be amplified.");
- gtk_box_pack_start(GTK_BOX(g->control_subbox), p->get_widget(), WID_FIX);
+ gtk_box_pack_start(GTK_BOX(g->fx_box), p->get_widget(), WID_FIX);
/* 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);
+ p=new tX_panel("Echo", g->fx_box);
+ g_signal_connect(G_OBJECT(p->get_labelbutton()), "pressed", 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));
p->add_client_widget(g->ec_pand->get_widget());
gui_set_tooltip(g->ec_pand->get_entry(), "Adjust the panning of the echo effect.");
- gtk_box_pack_start(GTK_BOX(g->control_subbox), p->get_widget(), WID_FIX);
+ gtk_box_pack_start(GTK_BOX(g->fx_box), p->get_widget(), WID_FIX);
+ g->stereo_fx_box=gtk_vbox_new(FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(g->control_subbox), g->stereo_fx_box, WID_FIX);
+ gtk_widget_show(g->stereo_fx_box);
+
+ dummy=gtk_button_new_with_label("Stereo FX");
+ gtk_container_foreach(GTK_CONTAINER(dummy), (GtkCallback) tX_panel_make_label_bold, NULL);
+ gtk_widget_show(dummy);
+ g->stereo_fx_button=dummy;
+ gui_set_tooltip(g->stereo_fx_button, "Click here to load a stereo LADSPA plugin. You will get a menu from which you can choose which plugin to load.");
+ gtk_box_pack_start(GTK_BOX(g->stereo_fx_box), dummy, WID_FIX);
+
/* Output */
tempbox=gtk_hbox_new(FALSE,2);
return box;
}
-
int gtk_box_get_widget_pos(GtkBox *box, GtkWidget *child)
{
int i=0;
return i;
}
-void vg_move_fx_panel_up(GtkWidget *wid, vtt_class *vtt)
+void vg_move_fx_panel_up(GtkWidget *wid, vtt_class *vtt, bool stereo)
{
- int pos=gtk_box_get_widget_pos(GTK_BOX(vtt->gui.control_subbox), wid);
- gtk_box_reorder_child(GTK_BOX(vtt->gui.control_subbox), wid, pos-1);
+ GtkWidget *box=(stereo ? vtt->gui.stereo_fx_box : vtt->gui.fx_box);
+ int pos=gtk_box_get_widget_pos(GTK_BOX(box), wid);
+ gtk_box_reorder_child(GTK_BOX(box), wid, pos-1);
}
-void vg_move_fx_panel_down(GtkWidget *wid, vtt_class *vtt)
+void vg_move_fx_panel_down(GtkWidget *wid, vtt_class *vtt, bool stereo)
{
- int pos=gtk_box_get_widget_pos(GTK_BOX(vtt->gui.control_subbox), wid);
- gtk_box_reorder_child(GTK_BOX(vtt->gui.control_subbox), wid, pos+1);
+ GtkWidget *box=(stereo ? vtt->gui.stereo_fx_box : vtt->gui.fx_box);
+ int pos=gtk_box_get_widget_pos(GTK_BOX(box), wid);
+ gtk_box_reorder_child(GTK_BOX(box), wid, pos+1);
}
void vg_show_fx_info(GtkWidget *wid, vtt_fx *effect)
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");
+ GtkWidget *item=gtk_menu_item_new_with_label("View Plugin Details");
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);
break;
}
- g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(vg_toggle_drywet), effect);
+ 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);
+ item = gtk_menu_item_new();
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+ gtk_widget_set_sensitive(item, FALSE);
+ gtk_widget_show(item);
+
+ item=gtk_menu_item_new_with_label("Up");
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+ gtk_widget_show(item);
+ g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(fx_up), effect);
+
+ item=gtk_menu_item_new_with_label("Down");
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
gtk_widget_show(item);
+ g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(fx_down), effect);
+
+ item=gtk_menu_item_new_with_label("Delete");
+ 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(fx_kill), effect);
gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 0, 0);
list <tX_seqpar_vttfx *> :: iterator sp;
strcpy(buffer, plugin->getLabel());
- if (strlen(buffer) > 6)
- {
+ if (strlen(buffer) > 6) {
buffer[5]='.';
buffer[6]='.';
buffer[7]='.';
p->add_client_widget(vg_create_fx_bar(vtt, effect, 1));
- for (sp = effect->controls.begin(); sp != effect->controls.end(); sp++)
- {
+ for (sp = effect->controls.begin(); sp != effect->controls.end(); sp++) {
p->add_client_widget((*sp)->get_widget());
}
- g_signal_connect(G_OBJECT(p->get_labelbutton()), "clicked", (GtkSignalFunc) vg_show_fx_menu, (void *) effect);
+ g_signal_connect(G_OBJECT(p->get_labelbutton()), "pressed", (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);
- gtk_box_pack_start(GTK_BOX(g->control_subbox), p->get_widget(), WID_FIX);
+ gtk_box_pack_start(GTK_BOX((effect->is_stereo() ? g->stereo_fx_box : g->fx_box)), p->get_widget(), WID_FIX);
}
void gui_set_filename (vtt_class *vtt, char *newname)
GtkWidget *control_minimize;
GtkWidget *scrolled_win;
GtkWidget *control_subbox;
+ GtkWidget *fx_box;
+ GtkWidget *stereo_fx_box;
GtkWidget *ladspa_menu;
GtkWidget *par_menu;
GtkWidget *del;
GtkWidget *adjust_button;
GtkWidget *fx_button;
+ GtkWidget *stereo_fx_button;
/* Trigger */
tX_panel *trigger_panel;