[SCM] gsequencer/master: added wishlist patches to enable output widgets to plugins

jkraehemann-guest at users.alioth.debian.org jkraehemann-guest at users.alioth.debian.org
Thu Feb 2 12:17:47 UTC 2017


The following commit has been merged in the master branch:
commit aac64d8096c2a3001f95f6eaef298da7afec29f4
Author: Joël Krähemann <jkraehemann-guest at users.alioth.debian.org>
Date:   Thu Feb 2 13:10:57 2017 +0100

    added wishlist patches to enable output widgets to plugins

diff --git a/debian/patches/series b/debian/patches/series
index 5b88c21..cad926e 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1,29 @@
+wish-recall-lv2.patch
+wish-recall-h.patch
+wish-recall-dssi.patch
+wish-peak-channel.patch
+wish-mixer-input-line.patch
+wish-lv2-browser-callbacks.patch
+wish-lv2-browser-h.patch
+wish-ladspa-browser-h.patch
+wish-lv2-browser-c.patch
+wish-line-member.patch
+wish-line-h.patch
+wish-line-callbacks-h.patch
+wish-line-callbacks-c.patch
+wish-line-c.patch
+wish-ladspa-browser-callbacks.patch
+wish-ladspa-browser-c.patch
+wish-hindicator.patch
+wish-effect-line-h.patch
+wish-effect-line-callbacks-h.patch
+wish-effect-line-callbacks-c.patch
+wish-effect-line-c.patch
+wish-effect-bulk-h.patch
+wish-effect-bulk-callbacks-h.patch
+wish-effect-bulk-callbacks-c.patch
+wish-effect-bulk-c.patch
+wish-drum-input-line.patch
 wish-volume-channel.patch
 wish-volume-audio-signal.patch
 wish-mute-channel.patch
diff --git a/debian/patches/wish-drum-input-line.patch b/debian/patches/wish-drum-input-line.patch
new file mode 100644
index 0000000..670b975
--- /dev/null
+++ b/debian/patches/wish-drum-input-line.patch
@@ -0,0 +1,44 @@
+Description: This is a wishlist patch. It changes the recall handler to the
+ generic callback, introduced in view of plugin output ports. It is responsible
+ for redrawing visible feedback.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/machine/ags_drum_input_line.c
++++ b/ags/X/machine/ags_drum_input_line.c
+@@ -101,7 +101,7 @@
+ static gpointer ags_drum_input_line_parent_class = NULL;
+ static AgsConnectableInterface *ags_drum_input_line_parent_connectable_interface;
+ 
+-extern GHashTable *ags_indicator_queue_draw;
++extern GHashTable *ags_line_indicator_queue_draw;
+ 
+ GType
+ ags_drum_input_line_get_type()
+@@ -211,7 +211,7 @@
+ 		   1, 1);
+   widget = gtk_bin_get_child(GTK_BIN(line_member));
+   AGS_LINE(drum_input_line)->indicator = widget;
+-  g_hash_table_insert(ags_indicator_queue_draw,
++  g_hash_table_insert(ags_line_indicator_queue_draw,
+ 		      widget, ags_line_indicator_queue_draw_timeout);
+   g_timeout_add(1000 / 30, (GSourceFunc) ags_line_indicator_queue_draw_timeout, (gpointer) widget);
+ 
+@@ -446,7 +446,7 @@
+     recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
+ 
+     recall_handler->signal_name = "run-post\0";
+-    recall_handler->callback = G_CALLBACK(ags_line_peak_run_post_callback);
++    recall_handler->callback = G_CALLBACK(ags_line_output_port_run_post_callback);
+     recall_handler->data = (gpointer) line;
+ 
+     ags_recall_add_handler(AGS_RECALL(play_peak_channel_run), recall_handler);
+@@ -462,7 +462,7 @@
+     recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
+ 
+     recall_handler->signal_name = "run-post\0";
+-    recall_handler->callback = G_CALLBACK(ags_line_peak_run_post_callback);
++    recall_handler->callback = G_CALLBACK(ags_line_output_port_run_post_callback);
+     recall_handler->data = (gpointer) line;
+ 
+     ags_recall_add_handler(AGS_RECALL(recall_peak_channel_run), recall_handler);
diff --git a/debian/patches/wish-effect-bulk-c.patch b/debian/patches/wish-effect-bulk-c.patch
new file mode 100644
index 0000000..38ae76b
--- /dev/null
+++ b/debian/patches/wish-effect-bulk-c.patch
@@ -0,0 +1,523 @@
+Description: This is a wishlist patch. It creates the output widgets available
+ in AgsLadspaBridge, AgsDssiBridge and AgsLv2Bridge or anyhow related to effect
+ bulk.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_effect_bulk.c
++++ b/ags/X/ags_effect_bulk.c
+@@ -65,6 +65,8 @@
+ #include <ags/audio/task/ags_add_recall_container.h>
+ #include <ags/audio/task/ags_add_recall.h>
+ 
++#include <ags/widget/ags_led.h>
++#include <ags/widget/ags_hindicator.h>
+ #include <ags/widget/ags_dial.h>
+ 
+ #include <ags/X/ags_window.h>
+@@ -105,6 +107,7 @@
+ void ags_effect_bulk_set_version(AgsPlugin *plugin, gchar *version);
+ gchar* ags_effect_bulk_get_build_id(AgsPlugin *plugin);
+ void ags_effect_bulk_set_build_id(AgsPlugin *plugin, gchar *build_id);
++void ags_effect_bulk_finalize(GObject *gobject);
+ void ags_effect_bulk_show(GtkWidget *widget);
+ 
+ GList* ags_effect_bulk_add_ladspa_effect(AgsEffectBulk *effect_bulk,
+@@ -165,6 +168,8 @@
+ static gpointer ags_effect_bulk_parent_class = NULL;
+ static guint effect_bulk_signals[LAST_SIGNAL];
+ 
++GHashTable *ags_effect_bulk_indicator_queue_draw = NULL;
++
+ GType
+ ags_effect_bulk_get_type(void)
+ {
+@@ -226,6 +231,7 @@
+   gobject->set_property = ags_effect_bulk_set_property;
+   gobject->get_property = ags_effect_bulk_get_property;
+ 
++  gobject->finalize = ags_effect_bulk_finalize;
+   
+   /* properties */
+   /**
+@@ -413,6 +419,12 @@
+ {
+   GtkAlignment *alignment;
+   GtkHBox *hbox;
++
++  if(ags_effect_bulk_indicator_queue_draw == NULL){
++    ags_effect_bulk_indicator_queue_draw = g_hash_table_new_full(g_direct_hash, g_direct_equal,
++								 NULL,
++								 NULL);
++  }
+   
+   effect_bulk->flags = 0;
+ 
+@@ -478,6 +490,8 @@
+ 		     0);
+ 
+   effect_bulk->plugin_browser = (GtkDialog *) ags_plugin_browser_new((GtkWidget *) effect_bulk);
++
++  effect_bulk->queued_drawing = NULL;
+ }
+ 
+ void
+@@ -698,6 +712,41 @@
+ }
+ 
+ void
++ags_effect_bulk_finalize(GObject *gobject)
++{
++  AgsEffectBulk *effect_bulk;
++
++  GList *list;
++  
++  effect_bulk = (AgsEffectBulk *) gobject;
++
++  /* unref audio */
++  if(effect_bulk->audio != NULL){
++    g_object_unref(effect_bulk->audio);
++  }
++
++  /* free plugin list */
++  g_list_free_full(effect_bulk,
++		   ags_effect_bulk_plugin_free);
++
++  /* destroy plugin browser */
++  gtk_widget_destroy(effect_bulk->plugin_browser);
++
++  /* remove of the queued drawing hash */
++  list = effect_bulk->queued_drawing;
++
++  while(list != NULL){
++    g_hash_table_remove(ags_effect_bulk_indicator_queue_draw,
++			list->data);
++
++    list = list->next;
++  }
++  
++  /* call parent */  
++  G_OBJECT_CLASS(ags_effect_bulk_parent_class)->finalize(gobject);
++}
++
++void
+ ags_effect_bulk_show(GtkWidget *widget)
+ {
+   AgsEffectBulk *effect_bulk;
+@@ -715,6 +764,17 @@
+   }
+ }
+ 
++/**
++ * ags_effect_bulk_plugin_alloc:
++ * @filename: the filename as string
++ * @effect: the effect as string
++ * 
++ * Allocate #AgsEffectBulkPlugin-struct.
++ * 
++ * Returns: the newly allocated #AgsEffectBulkPlugin-struct
++ * 
++ * Since: 0.7.128
++ */
+ AgsEffectBulkPlugin*
+ ags_effect_bulk_plugin_alloc(gchar *filename,
+ 			     gchar *effect)
+@@ -731,6 +791,36 @@
+   return(effect_plugin);
+ }
+ 
++/**
++ * ags_effect_bulk_plugin_free:
++ * @effect_bulk_plugin: the #AgsEffectBulkPlugin-struct
++ * 
++ * Free @effect_bulk_plugin.
++ * 
++ * Since: 0.7.128
++ */
++void
++ags_effect_bulk_plugin_free(AgsEffectBulkPlugin *effect_bulk_plugin)
++{
++  if(effect_bulk_plugin == NULL){
++    return;
++  }
++
++  if(effect_bulk_plugin->filename != NULL){
++    free(effect_bulk_plugin->filename);
++  }
++
++  if(effect_bulk_plugin->effect != NULL){
++    free(effect_bulk_plugin->effect);
++  }
++
++  if(effect_bulk_plugin->control_type_name != NULL){
++    g_list_free(effect_bulk_plugin->control_type_name);
++  }
++  
++  free(effect_bulk_plugin);
++}
++
+ GList*
+ ags_effect_bulk_add_ladspa_effect(AgsEffectBulk *effect_bulk,
+ 				  GList *control_type_name,
+@@ -748,6 +838,7 @@
+   AgsRecallContainer *recall_container;
+   AgsRecallChannelRunDummy *recall_channel_run_dummy;
+   AgsRecallLadspa *recall_ladspa;
++  AgsRecallHandler *recall_handler;
+ 
+   AgsAddRecallContainer *add_recall_container;
+   AgsAddRecall *add_recall;
+@@ -769,6 +860,8 @@
+   guint pads, audio_channels;
+   gdouble step;
+   guint port_count;
++  gboolean has_output_port;
++  
+   guint x, y;
+   guint i, j;
+   guint k;
+@@ -838,6 +931,8 @@
+ 
+   task = NULL;
+   retport = NULL;
++
++  has_output_port = FALSE;
+   
+   for(i = 0; i < pads; i++){
+     for(j = 0; j < audio_channels; j++){
+@@ -858,6 +953,7 @@
+ 					    filename,
+ 					    effect,
+ 					    AGS_BASE_PLUGIN(ladspa_plugin)->effect_index);
++
+       g_object_set(G_OBJECT(recall_ladspa),
+ 		   "soundcard\0", soundcard,
+ 		   "recall-container\0", recall_container,
+@@ -872,6 +968,10 @@
+ 
+       port = ags_recall_ladspa_load_ports(recall_ladspa);
+ 
++      if((AGS_RECALL_HAS_OUTPUT_PORT & (AGS_RECALL(recall_ladspa)->flags)) != 0){
++	has_output_port = TRUE;
++      }
++      
+       if(retport == NULL){
+ 	retport = port;
+       }else{
+@@ -905,6 +1005,17 @@
+ 			     FALSE);
+       ags_connectable_connect(AGS_CONNECTABLE(recall_channel_run_dummy));
+ 
++      /* recall handler of output port */
++      if(has_output_port){
++	recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
++
++	recall_handler->signal_name = "run-post\0";
++	recall_handler->callback = G_CALLBACK(ags_effect_bulk_output_port_run_post_callback);
++	recall_handler->data = (gpointer) effect_bulk;
++
++	ags_recall_add_handler(AGS_RECALL(recall_channel_run_dummy), recall_handler);
++      }
++      
+       /* ladspa recall */
+       recall_container = ags_recall_container_new();
+       ags_audio_add_recall_container(effect_bulk->audio,
+@@ -961,6 +1072,17 @@
+ 			     FALSE);
+       ags_connectable_connect(AGS_CONNECTABLE(recall_channel_run_dummy));
+ 
++      /* recall handler of output port */
++      if(has_output_port){
++	recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
++
++	recall_handler->signal_name = "run-post\0";
++	recall_handler->callback = G_CALLBACK(ags_effect_bulk_output_port_run_post_callback);
++	recall_handler->data = (gpointer) effect_bulk;
++
++	ags_recall_add_handler(AGS_RECALL(recall_channel_run_dummy), recall_handler);
++      }
++      
+       /* iterate */
+       pthread_mutex_lock(channel_mutex);
+       
+@@ -1010,9 +1132,17 @@
+       }
+       
+       if((AGS_PORT_DESCRIPTOR_TOGGLED & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
+-	widget_type = GTK_TYPE_TOGGLE_BUTTON;
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  widget_type = AGS_TYPE_LED;
++	}else{
++	  widget_type = GTK_TYPE_TOGGLE_BUTTON;
++	}
+       }else{
+-	widget_type = AGS_TYPE_DIAL;
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  widget_type = AGS_TYPE_HINDICATOR;
++	}else{
++	  widget_type = AGS_TYPE_DIAL;
++	}
+       }
+       
+       step_count = AGS_DIAL_DEFAULT_PRECISION;
+@@ -1129,6 +1259,13 @@
+ 	
+ 	gtk_adjustment_set_value(adjustment,
+ 				 default_value);
++      }else if(AGS_IS_INDICATOR(child_widget) ||
++	       AGS_IS_LED(child_widget)){
++	g_hash_table_insert(ags_effect_bulk_indicator_queue_draw,
++			    child_widget, ags_effect_bulk_indicator_queue_draw_timeout);
++	effect_bulk->queued_drawing = g_list_prepend(effect_bulk->queued_drawing,
++						     child_widget);
++	g_timeout_add(1000 / 30, (GSourceFunc) ags_effect_bulk_indicator_queue_draw_timeout, (gpointer) child_widget);
+       }
+ 
+ #ifdef AGS_DEBUG
+@@ -1176,6 +1313,7 @@
+   AgsRecallContainer *recall_container;
+   AgsRecallChannelRunDummy *recall_channel_run_dummy;
+   AgsRecallDssi *recall_dssi;
++  AgsRecallHandler *recall_handler;
+ 
+   AgsAddRecallContainer *add_recall_container;
+   AgsAddRecall *add_recall;
+@@ -1197,6 +1335,8 @@
+   guint pads, audio_channels;
+   gdouble step;
+   guint port_count;
++  gboolean has_output_port;
++  
+   guint x, y;
+   guint i, j;
+   guint k;
+@@ -1266,6 +1406,8 @@
+ 
+   task = NULL;
+   retport = NULL;
++
++  has_output_port = FALSE;
+   
+   for(i = 0; i < pads; i++){
+     for(j = 0; j < audio_channels; j++){
+@@ -1313,6 +1455,10 @@
+ 				port);
+       }
+ 
++      if((AGS_RECALL_HAS_OUTPUT_PORT & (AGS_RECALL(recall_dssi)->flags)) != 0){
++	has_output_port = TRUE;
++      }
++
+       ags_channel_add_recall(current,
+ 			     (GObject *) recall_dssi,
+ 			     TRUE);
+@@ -1338,7 +1484,18 @@
+ 			     (GObject *) recall_channel_run_dummy,
+ 			     TRUE);
+       ags_connectable_connect(AGS_CONNECTABLE(recall_channel_run_dummy));
++      
++      /* recall handler of output port */
++      if(has_output_port){
++	recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
++
++	recall_handler->signal_name = "run-post\0";
++	recall_handler->callback = G_CALLBACK(ags_effect_bulk_output_port_run_post_callback);
++	recall_handler->data = (gpointer) effect_bulk;
+ 
++	ags_recall_add_handler(AGS_RECALL(recall_channel_run_dummy), recall_handler);
++      }
++      
+       /* dssi recall */
+       recall_container = ags_recall_container_new();
+       ags_audio_add_recall_container(effect_bulk->audio,
+@@ -1401,6 +1558,17 @@
+ 			     FALSE);
+       ags_connectable_connect(AGS_CONNECTABLE(recall_channel_run_dummy));
+       
++      /* recall handler of output port */
++      if(has_output_port){
++	recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
++
++	recall_handler->signal_name = "run-post\0";
++	recall_handler->callback = G_CALLBACK(ags_effect_bulk_output_port_run_post_callback);
++	recall_handler->data = (gpointer) effect_bulk;
++
++	ags_recall_add_handler(AGS_RECALL(recall_channel_run_dummy), recall_handler);
++      }
++
+       /* iterate */
+       pthread_mutex_lock(channel_mutex);
+       
+@@ -1448,9 +1616,17 @@
+       }
+ 
+       if((AGS_PORT_DESCRIPTOR_TOGGLED & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
+-	widget_type = GTK_TYPE_TOGGLE_BUTTON;
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  widget_type = AGS_TYPE_LED;
++	}else{
++	  widget_type = GTK_TYPE_TOGGLE_BUTTON;
++	}
+       }else{
+-	widget_type = AGS_TYPE_DIAL;
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  widget_type = AGS_TYPE_HINDICATOR;
++	}else{
++	  widget_type = AGS_TYPE_DIAL;
++	}
+       }
+ 
+       step_count = AGS_DIAL_DEFAULT_PRECISION;
+@@ -1571,6 +1747,13 @@
+ #ifdef AGS_DEBUG
+ 	g_message("dssi bounds: %f %f\0", lower_bound, upper_bound);
+ #endif
++      }else if(AGS_IS_INDICATOR(child_widget) ||
++	       AGS_IS_LED(child_widget)){
++	g_hash_table_insert(ags_effect_bulk_indicator_queue_draw,
++			    child_widget, ags_effect_bulk_indicator_queue_draw_timeout);
++	effect_bulk->queued_drawing = g_list_prepend(effect_bulk->queued_drawing,
++						     child_widget);
++	g_timeout_add(1000 / 30, (GSourceFunc) ags_effect_bulk_indicator_queue_draw_timeout, (gpointer) child_widget);
+       }
+ 
+       gtk_table_attach(effect_bulk->table,
+@@ -1614,6 +1797,7 @@
+   AgsRecallContainer *recall_container;
+   AgsRecallChannelRunDummy *recall_channel_run_dummy;
+   AgsRecallLv2 *recall_lv2;
++  AgsRecallHandler *recall_handler;
+ 
+   AgsAddRecallContainer *add_recall_container;
+   AgsAddRecall *add_recall;
+@@ -1641,6 +1825,8 @@
+   gdouble step;
+   guint pads, audio_channels;
+   guint port_count;
++  gboolean has_output_port;
++
+   guint x, y;
+   guint i, j;
+   guint k;
+@@ -1712,6 +1898,8 @@
+ 
+   task = NULL;
+   retport = NULL;
++
++  has_output_port = FALSE;
+   
+   for(i = 0; i < pads; i++){
+     for(j = 0; j < audio_channels; j++){
+@@ -1761,6 +1949,10 @@
+ 				port);
+       }
+ 
++      if((AGS_RECALL_HAS_OUTPUT_PORT & (AGS_RECALL(recall_lv2)->flags)) != 0){
++	has_output_port = TRUE;
++      }
++      
+       ags_channel_add_recall(current,
+ 			     (GObject *) recall_lv2,
+ 			     TRUE);
+@@ -1787,6 +1979,17 @@
+ 			     TRUE);
+       ags_connectable_connect(AGS_CONNECTABLE(recall_channel_run_dummy));
+ 
++      /* recall handler of output port */
++      if(has_output_port){
++	recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
++
++	recall_handler->signal_name = "run-post\0";
++	recall_handler->callback = G_CALLBACK(ags_effect_bulk_output_port_run_post_callback);
++	recall_handler->data = (gpointer) effect_bulk;
++
++	ags_recall_add_handler(AGS_RECALL(recall_channel_run_dummy), recall_handler);
++      }
++
+       /* lv2 recall */
+       recall_container = ags_recall_container_new();
+       ags_audio_add_recall_container(effect_bulk->audio,
+@@ -1850,7 +2053,18 @@
+ 			     (GObject *) recall_channel_run_dummy,
+ 			     FALSE);
+       ags_connectable_connect(AGS_CONNECTABLE(recall_channel_run_dummy));
+-      
++
++      /* recall handler of output port */
++      if(has_output_port){
++	recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
++
++	recall_handler->signal_name = "run-post\0";
++	recall_handler->callback = G_CALLBACK(ags_effect_bulk_output_port_run_post_callback);
++	recall_handler->data = (gpointer) effect_bulk;
++
++	ags_recall_add_handler(AGS_RECALL(recall_channel_run_dummy), recall_handler);
++      }
++
+       /* iterate */
+       pthread_mutex_lock(channel_mutex);
+       
+@@ -1898,9 +2112,17 @@
+       }
+ 
+       if((AGS_PORT_DESCRIPTOR_TOGGLED & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
+-	widget_type = GTK_TYPE_TOGGLE_BUTTON;
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  widget_type = AGS_TYPE_LED;
++	}else{
++	  widget_type = GTK_TYPE_TOGGLE_BUTTON;
++	}
+       }else{
+-	widget_type = AGS_TYPE_DIAL;
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  widget_type = AGS_TYPE_HINDICATOR;
++	}else{
++	  widget_type = AGS_TYPE_DIAL;
++	}
+       }
+ 
+       step_count = AGS_DIAL_DEFAULT_PRECISION;
+@@ -1980,6 +2202,13 @@
+ 				 upper_bound);
+ 	gtk_adjustment_set_value(adjustment,
+ 				 g_value_get_float(AGS_PORT_DESCRIPTOR(port_descriptor->data)->default_value));
++      }else if(AGS_IS_INDICATOR(child_widget) ||
++	       AGS_IS_LED(child_widget)){
++	g_hash_table_insert(ags_effect_bulk_indicator_queue_draw,
++			    child_widget, ags_effect_bulk_indicator_queue_draw_timeout);
++	effect_bulk->queued_drawing = g_list_prepend(effect_bulk->queued_drawing,
++						     child_widget);
++	g_timeout_add(1000 / 30, (GSourceFunc) ags_effect_bulk_indicator_queue_draw_timeout, (gpointer) child_widget);
+       }
+ 
+ #ifdef AGS_DEBUG
+@@ -2652,6 +2881,29 @@
+ }
+ 
+ /**
++ * ags_effect_bulk_indicator_queue_draw_timeout:
++ * @widget: the indicator widgt
++ *
++ * Queue draw widget
++ *
++ * Returns: %TRUE if proceed with redraw, otherwise %FALSE
++ *
++ * Since: 0.7.128
++ */
++gboolean
++ags_effect_bulk_indicator_queue_draw_timeout(GtkWidget *widget)
++{
++  if(g_hash_table_lookup(ags_effect_bulk_indicator_queue_draw,
++			 widget) != NULL){
++    gtk_widget_queue_draw(widget);
++    
++    return(TRUE);
++  }else{
++    return(FALSE);
++  }
++}
++
++/**
+  * ags_effect_bulk_new:
+  * @audio: the #AgsAudio to visualize
+  * @channel_type: either %AGS_TYPE_INPUT or %AGS_TYPE_OUTPUT
diff --git a/debian/patches/wish-effect-bulk-callbacks-c.patch b/debian/patches/wish-effect-bulk-callbacks-c.patch
new file mode 100644
index 0000000..5550aad
--- /dev/null
+++ b/debian/patches/wish-effect-bulk-callbacks-c.patch
@@ -0,0 +1,163 @@
+Description: This is a wishlist patch. It provides update functionality of the
+ output widgets available to plugins like LADSPA, DSSI or Lv2.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_effect_bulk_callbacks.c
++++ b/ags/X/ags_effect_bulk_callbacks.c
+@@ -1,5 +1,5 @@
+ /* GSequencer - Advanced GTK Sequencer
+- * Copyright (C) 2005-2015 Joël Krähemann
++ * Copyright (C) 2005-2015,2017 Joël Krähemann
+  *
+  * This file is part of GSequencer.
+  *
+@@ -19,7 +19,18 @@
+ 
+ #include <ags/X/ags_effect_bulk_callbacks.h>
+ 
++#include <ags/plugin/ags_base_plugin.h>
++
++#include <ags/audio/ags_audio.h>
++#include <ags/audio/ags_channel.h>
++#include <ags/audio/ags_port.h>
++
++#include <ags/widget/ags_led.h>
++#include <ags/widget/ags_vindicator.h>
++#include <ags/widget/ags_hindicator.h>
++
+ #include <ags/X/ags_machine.h>
++#include <ags/X/ags_bulk_member.h>
+ #include <ags/X/ags_plugin_browser.h>
+ 
+ void
+@@ -149,3 +160,129 @@
+ 				pads_old);    
+   }
+ }
++
++void
++ags_effect_bulk_output_port_run_post_callback(AgsRecall *recall,
++					      AgsEffectBulk *effect_bulk)
++{
++  GtkWidget *child;
++
++  GList *list, *list_start;
++  GList *port, *port_start;
++
++  /* lock gdk threads */
++  gdk_threads_enter();
++  
++  list_start = 
++    list = gtk_container_get_children((GtkContainer *) effect_bulk->table);
++
++  /* check members */
++  while(list != NULL){
++    if(AGS_IS_BULK_MEMBER(list->data) &&
++       (AGS_BULK_MEMBER(list->data)->widget_type == AGS_TYPE_VINDICATOR ||
++	AGS_BULK_MEMBER(list->data)->widget_type == AGS_TYPE_HINDICATOR ||
++	AGS_BULK_MEMBER(list->data)->widget_type == AGS_TYPE_LED)){
++      GtkAdjustment *adjustment;
++
++      gdouble average_peak;
++      
++      child = GTK_BIN(list->data)->child;
++      
++      average_peak = 0.0;
++      
++      /* copy port list */
++      port_start = g_list_concat(g_list_copy(AGS_BULK_MEMBER(list->data)->bulk_port),
++				 g_list_copy(AGS_BULK_MEMBER(list->data)->recall_bulk_port));
++
++      /* get display value */
++      port = port_start;
++	
++      while(port != NULL){
++	AgsPort *current;
++	
++	gdouble lower, upper;
++	gdouble range;
++	gdouble peak;
++	  
++	GValue value = {0,};
++
++	current = AGS_BULK_PORT(port->data)->port;
++
++	if(current == NULL){
++	  port = port->next;
++	
++	  continue;
++	}      
++	
++	/* check if output port and specifier matches */
++	pthread_mutex_lock(current->mutex);
++
++	if((AGS_PORT_IS_OUTPUT & (current->flags)) == 0 ||
++	   current->port_descriptor == NULL ||
++	   g_ascii_strcasecmp(current->specifier,
++			      AGS_BULK_MEMBER(list->data)->specifier)){
++	  pthread_mutex_unlock(current->mutex);
++	    
++	  port = port->next;
++
++	  continue;
++	}
++
++	/* lower and upper */
++	lower = g_value_get_float(AGS_PORT_DESCRIPTOR(current->port_descriptor)->lower_value);
++	upper = g_value_get_float(AGS_PORT_DESCRIPTOR(current->port_descriptor)->upper_value);
++	  
++	pthread_mutex_unlock(current->mutex);
++
++	/* get range */
++	range = upper - lower;
++
++	/* port read value */
++	g_value_init(&value, G_TYPE_FLOAT);
++	ags_port_safe_read(current,
++			   &value);
++	  
++	peak = g_value_get_float(&value);
++	g_value_unset(&value);
++
++	/* calculate peak */
++	if(range == 0.0 ||
++	   current->port_value_type == G_TYPE_BOOLEAN){
++	  if(peak != 0.0){
++	    average_peak = 10.0;
++	    break;
++	  }
++	}else{
++	  average_peak += ((1.0 / (range / peak)) * 10.0);
++	}
++
++	/* iterate port */
++	port = port->next;
++      }
++
++      g_list_free(port_start);
++      
++      /* apply */
++      if(AGS_IS_LED(child)){
++	if(average_peak != 0.0){
++	  ags_led_set_active(child);
++	}
++      }else{
++	g_object_get(child,
++		     "adjustment\0", &adjustment,
++		     NULL);
++	
++	gtk_adjustment_set_value(adjustment,
++				 average_peak);
++      }
++    }
++
++    /* iterate bulk member */
++    list = list->next;
++  }
++
++  g_list_free(list_start);
++
++  /* unlock gdk threads */
++  gdk_threads_leave();
++}
diff --git a/debian/patches/wish-effect-bulk-callbacks-h.patch b/debian/patches/wish-effect-bulk-callbacks-h.patch
new file mode 100644
index 0000000..fe837b1
--- /dev/null
+++ b/debian/patches/wish-effect-bulk-callbacks-h.patch
@@ -0,0 +1,35 @@
+Description: This is a wishlist patch. It provides the function declaration of
+ the update functionality of output widgets.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_effect_bulk_callbacks.h
++++ b/ags/X/ags_effect_bulk_callbacks.h
+@@ -1,5 +1,5 @@
+ /* GSequencer - Advanced GTK Sequencer
+- * Copyright (C) 2005-2015 Joël Krähemann
++ * Copyright (C) 2005-2015,2017 Joël Krähemann
+  *
+  * This file is part of GSequencer.
+  *
+@@ -22,10 +22,10 @@
+ 
+ #include <glib.h>
+ #include <glib-object.h>
++
+ #include <gtk/gtk.h>
+ 
+-#include <lv2.h>
+-#include <lv2/lv2plug.in/ns/extensions/ui/ui.h>
++#include <ags/audio/ags_recall.h>
+ 
+ #include <ags/X/ags_effect_bulk.h>
+ 
+@@ -48,4 +48,7 @@
+ 				       guint pads_old,
+ 				       AgsEffectBulk *effect_bulk);
+ 
++void ags_effect_bulk_output_port_run_post_callback(AgsRecall *recall,
++						   AgsEffectBulk *effect_bulk);
++
+ #endif /*__AGS_EFFECT_BULK_CALLBACKS_H__*/
diff --git a/debian/patches/wish-effect-bulk-h.patch b/debian/patches/wish-effect-bulk-h.patch
new file mode 100644
index 0000000..f0e1cbb
--- /dev/null
+++ b/debian/patches/wish-effect-bulk-h.patch
@@ -0,0 +1,33 @@
+Description: This is a wishlist patch. It provides the declaration of redrawing
+ function of output widgets.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_effect_bulk.h
++++ b/ags/X/ags_effect_bulk.h
+@@ -76,6 +76,8 @@
+ 
+   GList *plugin;
+   GtkDialog *plugin_browser;
++
++  GList *queued_drawing;
+ };
+ 
+ struct _AgsEffectBulkClass
+@@ -112,6 +114,7 @@
+ 
+ AgsEffectBulkPlugin* ags_effect_bulk_plugin_alloc(gchar *filename,
+ 						  gchar *effect);
++void ags_effect_bulk_plugin_free(AgsEffectBulkPlugin *effect_bulk_plugin);
+ 
+ GList* ags_effect_bulk_add_effect(AgsEffectBulk *effect_bulk,
+ 				  GList *control_type_name,
+@@ -130,6 +133,8 @@
+ void ags_effect_bulk_map_recall(AgsEffectBulk *effect_bulk);
+ GList* ags_effect_bulk_find_port(AgsEffectBulk *effect_bulk);
+ 
++gboolean ags_effect_bulk_indicator_queue_draw_timeout(GtkWidget *widget);
++
+ AgsEffectBulk* ags_effect_bulk_new(AgsAudio *audio,
+ 				   GType channel_type);
+ 
diff --git a/debian/patches/wish-effect-line-c.patch b/debian/patches/wish-effect-line-c.patch
new file mode 100644
index 0000000..fe8d0d4
--- /dev/null
+++ b/debian/patches/wish-effect-line-c.patch
@@ -0,0 +1,402 @@
+Description: This is a wishlist patch. It creates the output widgets available
+ in provided by a plugin added by user via machine editor.
+ AgsFFPlayer and AgsSynth use this widget to enable the user to assign plugins
+ to input lines.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_effect_line.c
++++ b/ags/X/ags_effect_line.c
+@@ -43,9 +43,13 @@
+ #include <ags/audio/ags_channel.h>
+ #include <ags/audio/ags_output.h>
+ #include <ags/audio/ags_input.h>
++#include <ags/audio/ags_recall_container.h>
+ #include <ags/audio/ags_recall_ladspa.h>
+ #include <ags/audio/ags_recall_lv2.h>
+ 
++#include <ags/widget/ags_led.h>
++#include <ags/widget/ags_vindicator.h>
++#include <ags/widget/ags_hindicator.h>
+ #include <ags/widget/ags_dial.h>
+ 
+ #include <ags/X/ags_window.h>
+@@ -83,6 +87,7 @@
+ void ags_effect_line_set_version(AgsPlugin *plugin, gchar *version);
+ gchar* ags_effect_line_get_build_id(AgsPlugin *plugin);
+ void ags_effect_line_set_build_id(AgsPlugin *plugin, gchar *build_id);
++void ags_effect_line_finalize(GObject *gobject);
+ 
+ GList* ags_effect_line_add_ladspa_effect(AgsEffectLine *effect_line,
+ 					 GList *control_type_name,
+@@ -129,6 +134,8 @@
+ static gpointer ags_effect_line_parent_class = NULL;
+ static guint effect_line_signals[LAST_SIGNAL];
+ 
++GHashTable *ags_effect_line_indicator_queue_draw = NULL;
++
+ GType
+ ags_effect_line_get_type(void)
+ {
+@@ -189,6 +196,8 @@
+   gobject->set_property = ags_effect_line_set_property;
+   gobject->get_property = ags_effect_line_get_property;
+ 
++  gobject->finalize = ags_effect_line_finalize;
++  
+   /* properties */
+   /**
+    * AgsEffectLine:channel:
+@@ -349,6 +358,8 @@
+ 		     GTK_WIDGET(effect_line->table),
+ 		     FALSE, FALSE,
+ 		     0);
++
++  effect_line->queued_drawing = NULL;
+ }
+ 
+ void
+@@ -537,6 +548,25 @@
+   effect_line->build_id = build_id;
+ }
+ 
++void
++ags_effect_line_finalize(GObject *gobject)
++{
++  AgsEffectLine *effect_line;
++  GList *list;
++
++  effect_line = AGS_EFFECT_LINE(gobject);
++  
++  /* remove of the queued drawing hash */
++  list = effect_line->queued_drawing;
++
++  while(list != NULL){
++    g_hash_table_remove(ags_effect_line_indicator_queue_draw,
++			list->data);
++
++    list = list->next;
++  }
++}
++
+ GList*
+ ags_effect_line_add_ladspa_effect(AgsEffectLine *effect_line,
+ 				  GList *control_type_name,
+@@ -547,6 +577,8 @@
+   AgsAddLineMember *add_line_member;
+   GtkAdjustment *adjustment;
+ 
++  AgsRecallHandler *recall_handler;
++
+   AgsLadspaPlugin *ladspa_plugin;
+ 
+   AgsMutexManager *mutex_manager;
+@@ -558,11 +590,17 @@
+   
+   gdouble step;
+   guint port_count;
++  gboolean has_output_port;
++
+   guint x, y;
+   guint k;
+   
+   pthread_mutex_t *application_mutex;
+   pthread_mutex_t *channel_mutex;
++
++  /* get mutex manager and application mutex */
++  mutex_manager = ags_mutex_manager_get_instance();
++  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
+   
+   /* load plugin */
+   ladspa_plugin = ags_ladspa_manager_find_ladspa_plugin(ags_ladspa_manager_get_instance(),
+@@ -582,10 +620,6 @@
+     list = list->next;
+   }
+ 
+-  /* get mutex manager and application mutex */
+-  mutex_manager = ags_mutex_manager_get_instance();
+-  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
+-
+   /* get channel mutex */
+   pthread_mutex_lock(application_mutex);
+ 
+@@ -594,13 +628,44 @@
+   
+   pthread_mutex_unlock(application_mutex);
+   
+-  /* find ports */
++  /* play - find ports */
+   pthread_mutex_lock(channel_mutex);
+ 
+   recall_start =
+     recall = ags_recall_get_by_effect(effect_line->channel->play,
+ 				      filename,
+ 				      effect);
++
++  if(recall == NULL){
++    pthread_mutex_unlock(channel_mutex);
++    
++    return(NULL);
++  }
++
++  /* check has output port */
++  if((AGS_RECALL_HAS_OUTPUT_PORT & (AGS_RECALL(recall->data)->flags)) != 0){
++    has_output_port = TRUE;
++  }else{
++    has_output_port = FALSE;
++  }
++
++  /* recall handler of output port */
++  if(has_output_port){
++    AgsRecall *recall_channel_run_dummy;
++
++    recall_channel_run_dummy = ags_recall_find_template(AGS_RECALL_CONTAINER(AGS_RECALL(recall->data)->container)->recall_channel_run)->data;
++    
++    /* alloc handler */
++    recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
++
++    recall_handler->signal_name = "run-post\0";
++    recall_handler->callback = G_CALLBACK(ags_effect_line_output_port_run_post_callback);
++    recall_handler->data = (gpointer) effect_line;
++
++    ags_recall_add_handler(AGS_RECALL(recall_channel_run_dummy), recall_handler);
++  }
++  
++  /* recall - find ports */
+   recall = g_list_last(recall);
+   port = AGS_RECALL(recall->data)->port;
+ 
+@@ -617,6 +682,22 @@
+ 
+   pthread_mutex_unlock(channel_mutex);
+ 
++  /* recall handler of output port */
++  if(has_output_port){
++    AgsRecall *recall_channel_run_dummy;
++
++    recall_channel_run_dummy = ags_recall_find_template(AGS_RECALL_CONTAINER(AGS_RECALL(recall->data)->container)->recall_channel_run)->data;
++    
++    /* alloc handler */
++    recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
++
++    recall_handler->signal_name = "run-post\0";
++    recall_handler->callback = G_CALLBACK(ags_effect_line_output_port_run_post_callback);
++    recall_handler->data = (gpointer) effect_line;
++
++    ags_recall_add_handler(AGS_RECALL(recall_channel_run_dummy), recall_handler);
++  }
++
+   /* load ports */
+   port_descriptor = AGS_BASE_PLUGIN(ladspa_plugin)->port;
+ 
+@@ -641,9 +722,17 @@
+       }
+       
+       if((AGS_PORT_DESCRIPTOR_TOGGLED & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
+-	widget_type = GTK_TYPE_TOGGLE_BUTTON;
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  widget_type = AGS_TYPE_LED;
++	}else{
++	  widget_type = GTK_TYPE_TOGGLE_BUTTON;
++	}
+       }else{
+-	widget_type = AGS_TYPE_DIAL;
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  widget_type = AGS_TYPE_HINDICATOR;
++	}else{
++	  widget_type = AGS_TYPE_DIAL;
++	}
+       }
+ 
+       if(control_type_name != NULL){
+@@ -754,6 +843,13 @@
+ 				 upper_bound);
+ 	gtk_adjustment_set_value(adjustment,
+ 				 g_value_get_float(AGS_PORT_DESCRIPTOR(port_descriptor->data)->default_value));
++      }else if(AGS_IS_INDICATOR(child_widget) ||
++	       AGS_IS_LED(child_widget)){
++	g_hash_table_insert(ags_effect_line_indicator_queue_draw,
++			    child_widget, ags_effect_line_indicator_queue_draw_timeout);
++	effect_line->queued_drawing = g_list_prepend(effect_line->queued_drawing,
++						     child_widget);
++	g_timeout_add(1000 / 30, (GSourceFunc) ags_effect_line_indicator_queue_draw_timeout, (gpointer) child_widget);
+       }
+ 
+ #ifdef AGS_DEBUG
+@@ -792,6 +888,8 @@
+   AgsAddLineMember *add_line_member;
+   GtkAdjustment *adjustment;
+ 
++  AgsRecallHandler *recall_handler;
++
+   AgsLv2Plugin *lv2_plugin;
+ 
+   AgsMutexManager *mutex_manager;
+@@ -803,12 +901,18 @@
+   
+   gdouble step;
+   guint port_count;
++  gboolean has_output_port;
++
+   guint x, y;
+   guint k;
+   
+   pthread_mutex_t *application_mutex;
+   pthread_mutex_t *channel_mutex;
+ 
++  /* get mutex manager and application mutex */
++  mutex_manager = ags_mutex_manager_get_instance();
++  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
++
+   /* load plugin */
+   lv2_plugin = ags_lv2_manager_find_lv2_plugin(ags_lv2_manager_get_instance(),
+ 					       filename, effect);
+@@ -827,10 +931,6 @@
+     list = list->next;
+   }
+ 
+-  /* get mutex manager and application mutex */
+-  mutex_manager = ags_mutex_manager_get_instance();
+-  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
+-
+   /* get channel mutex */
+   pthread_mutex_lock(application_mutex);
+ 
+@@ -839,18 +939,49 @@
+   
+   pthread_mutex_unlock(application_mutex);
+   
+-  /* find ports */
++  /* play - find ports */
+   pthread_mutex_lock(channel_mutex);
+   
+   recall_start =
+     recall = ags_recall_get_by_effect(effect_line->channel->play,
+ 				      filename,
+ 				      effect);
++
++  if(recall == NULL){
++    pthread_mutex_unlock(channel_mutex);
++    
++    return(NULL);
++  }
++
+   recall = g_list_last(recall);
+   port = AGS_RECALL(recall->data)->port;
+ 
+   g_list_free(recall_start);
+ 
++  /* check has output port */
++  if((AGS_RECALL_HAS_OUTPUT_PORT & (AGS_RECALL(recall->data)->flags)) != 0){
++    has_output_port = TRUE;
++  }else{
++    has_output_port = FALSE;
++  }
++
++  /* recall handler of output port */
++  if(has_output_port){
++    AgsRecall *recall_channel_run_dummy;
++
++    recall_channel_run_dummy = ags_recall_find_template(AGS_RECALL_CONTAINER(AGS_RECALL(recall->data)->container)->recall_channel_run);
++    
++    /* alloc handler */
++    recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
++
++    recall_handler->signal_name = "run-post\0";
++    recall_handler->callback = G_CALLBACK(ags_effect_line_output_port_run_post_callback);
++    recall_handler->data = (gpointer) effect_line;
++
++    ags_recall_add_handler(AGS_RECALL(recall_channel_run_dummy), recall_handler);
++  }
++
++  /* recall - find ports */
+   recall_start = 
+     recall = ags_recall_get_by_effect(effect_line->channel->recall,
+ 				      filename,
+@@ -861,6 +992,22 @@
+   g_list_free(recall_start);
+ 
+   pthread_mutex_unlock(channel_mutex);
++
++  /* recall handler of output port */
++  if(has_output_port){
++    AgsRecall *recall_channel_run_dummy;
++
++    recall_channel_run_dummy = ags_recall_find_template(AGS_RECALL_CONTAINER(AGS_RECALL(recall->data)->container)->recall_channel_run);
++    
++    /* alloc handler */
++    recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
++
++    recall_handler->signal_name = "run-post\0";
++    recall_handler->callback = G_CALLBACK(ags_effect_line_output_port_run_post_callback);
++    recall_handler->data = (gpointer) effect_line;
++
++    ags_recall_add_handler(AGS_RECALL(recall_channel_run_dummy), recall_handler);
++  }
+   
+   /* load ports */
+   port_descriptor = AGS_BASE_PLUGIN(lv2_plugin)->port;
+@@ -887,9 +1034,17 @@
+       }
+ 
+       if((AGS_PORT_DESCRIPTOR_TOGGLED & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
+-	widget_type = GTK_TYPE_TOGGLE_BUTTON;
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  widget_type = AGS_TYPE_LED;
++	}else{
++	  widget_type = GTK_TYPE_TOGGLE_BUTTON;
++	}
+       }else{
+-	widget_type = AGS_TYPE_DIAL;
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  widget_type = AGS_TYPE_HINDICATOR;
++	}else{
++	  widget_type = AGS_TYPE_DIAL;
++	}
+       }
+ 
+       if(control_type_name != NULL){
+@@ -975,6 +1130,13 @@
+ 				 upper_bound);
+ 	gtk_adjustment_set_value(adjustment,
+ 				 g_value_get_float(AGS_PORT_DESCRIPTOR(port_descriptor->data)->default_value));
++      }else if(AGS_IS_INDICATOR(child_widget) ||
++	       AGS_IS_LED(child_widget)){
++	g_hash_table_insert(ags_effect_line_indicator_queue_draw,
++			    child_widget, ags_effect_line_indicator_queue_draw_timeout);
++	effect_line->queued_drawing = g_list_prepend(effect_line->queued_drawing,
++						     child_widget);
++	g_timeout_add(1000 / 30, (GSourceFunc) ags_effect_line_indicator_queue_draw_timeout, (gpointer) child_widget);
+       }
+ 
+ #ifdef AGS_DEBUG
+@@ -1327,6 +1489,29 @@
+ }
+ 
+ /**
++ * ags_effect_line_indicator_queue_draw_timeout:
++ * @widget: the indicator widgt
++ *
++ * Queue draw widget
++ *
++ * Returns: %TRUE if proceed with redraw, otherwise %FALSE
++ *
++ * Since: 0.7.128
++ */
++gboolean
++ags_effect_line_indicator_queue_draw_timeout(GtkWidget *widget)
++{
++  if(g_hash_table_lookup(ags_effect_line_indicator_queue_draw,
++			 widget) != NULL){
++    gtk_widget_queue_draw(widget);
++    
++    return(TRUE);
++  }else{
++    return(FALSE);
++  }
++}
++
++/**
+  * ags_effect_line_new:
+  * @channel: the #AgsChannel to visualize
+  *
diff --git a/debian/patches/wish-effect-line-callbacks-c.patch b/debian/patches/wish-effect-line-callbacks-c.patch
new file mode 100644
index 0000000..4e684cf
--- /dev/null
+++ b/debian/patches/wish-effect-line-callbacks-c.patch
@@ -0,0 +1,196 @@
+Description: This is a wishlist patch. It provides update functionality of the
+ output widgets available to plugins like LADSPA, DSSI or Lv2.
+ This widget is used currently by AgsFFPlayer and AgsSynth.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_effect_line_callbacks.c
++++ b/ags/X/ags_effect_line_callbacks.c
+@@ -22,8 +22,7 @@
+ #include <ags/object/ags_application_context.h>
+ #include <ags/object/ags_soundcard.h>
+ 
+-#include <ags/thread/ags_mutex_manager.h>
+-#include <ags/thread/ags_task_thread.h>
++#include <ags/plugin/ags_base_plugin.h>
+ 
+ #include <ags/audio/ags_playback.h>
+ #include <ags/audio/ags_recall.h>
+@@ -41,8 +40,10 @@
+ #include <ags/audio/recall/ags_copy_pattern_channel.h>
+ #include <ags/audio/recall/ags_copy_pattern_channel_run.h>
+ 
+-#include <ags/widget/ags_indicator.h>
++#include <ags/widget/ags_led.h>
+ #include <ags/widget/ags_vindicator.h>
++#include <ags/widget/ags_hindicator.h>
++#include <ags/widget/ags_dial.h>
+ 
+ #include <ags/X/ags_window.h>
+ #include <ags/X/ags_machine.h>
+@@ -58,8 +59,6 @@
+ #include <ags/X/ags_dssi_browser.h>
+ #include <ags/X/ags_lv2_browser.h>
+ 
+-#include <ags/X/task/ags_change_indicator.h>
+-
+ void
+ ags_effect_line_remove_recall_callback(AgsRecall *recall, AgsEffectLine *effect_line)
+ {
+@@ -162,6 +161,21 @@
+ 	      controls = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(port_control->data));
+ 
+ 	      if(!g_ascii_strncasecmp(controls,
++				      "led\0",
++				      4)){
++		control_type_name = g_list_prepend(control_type_name,
++						   "AgsLed\0");
++	      }else if(!g_ascii_strncasecmp(controls,
++				      "vertical indicator\0",
++				      19)){
++		control_type_name = g_list_prepend(control_type_name,
++						   "AgsVIndicator\0");
++	      }else if(!g_ascii_strncasecmp(controls,
++				      "horizontal indicator\0",
++				      19)){
++		control_type_name = g_list_prepend(control_type_name,
++						   "AgsHIndicator\0");
++	      }else if(!g_ascii_strncasecmp(controls,
+ 				      "spin button\0",
+ 				      12)){
+ 		control_type_name = g_list_prepend(control_type_name,
+@@ -238,4 +252,134 @@
+ 
+   /* unlock gdk threads */
+   gdk_threads_leave();
++}
++
++void
++ags_effect_line_output_port_run_post_callback(AgsRecall *recall,
++					      AgsEffectLine *effect_line)
++{
++  GtkWidget *child;
++
++  GList *list, *list_start;
++  
++  /* lock gdk threads */
++  gdk_threads_enter();
++  
++  list_start = 
++    list = gtk_container_get_children((GtkContainer *) AGS_EFFECT_LINE(effect_line)->table);
++
++  /* check members */
++  while(list != NULL){
++    if(AGS_IS_LINE_MEMBER(list->data) &&
++       (AGS_LINE_MEMBER(list->data)->widget_type == AGS_TYPE_VINDICATOR ||
++	AGS_LINE_MEMBER(list->data)->widget_type == AGS_TYPE_HINDICATOR ||
++	AGS_LINE_MEMBER(list->data)->widget_type == AGS_TYPE_LED)){
++      GtkAdjustment *adjustment;
++
++      AgsPort *current;
++	
++      gdouble average_peak;
++      gdouble lower, upper;
++      gdouble range;
++      gdouble peak;
++
++      GValue value = {0,};
++
++      child = GTK_BIN(list->data)->child;
++      
++      average_peak = 0.0;
++      
++      /* play port */
++      current = AGS_LINE_MEMBER(list->data)->port;
++
++      if(current == NULL){
++	list = list->next;
++	
++	continue;
++      }
++      
++      /* check if output port and specifier matches */
++      pthread_mutex_lock(current->mutex);
++      
++      if((AGS_PORT_IS_OUTPUT & (current->flags)) == 0 ||
++	 current->port_descriptor == NULL ||
++	 g_ascii_strcasecmp(current->specifier,
++			    AGS_LINE_MEMBER(list->data)->specifier)){
++	pthread_mutex_unlock(current->mutex);
++	
++	list = list->next;
++	
++	continue;
++      }
++
++      /* lower and upper */
++      lower = g_value_get_float(AGS_PORT_DESCRIPTOR(current->port_descriptor)->lower_value);
++      upper = g_value_get_float(AGS_PORT_DESCRIPTOR(current->port_descriptor)->upper_value);
++      
++      pthread_mutex_unlock(current->mutex);
++
++      /* get range */
++      range = upper - lower;
++
++      /* play port - read value */
++      g_value_init(&value, G_TYPE_FLOAT);
++      ags_port_safe_read(current,
++			 &value);
++      
++      peak = g_value_get_float(&value);
++      g_value_unset(&value);
++
++      /* calculate peak */
++      if(range == 0.0 ||
++	 current->port_value_type == G_TYPE_BOOLEAN){
++	if(peak != 0.0){
++	  average_peak = 10.0;
++	}
++      }else{
++	average_peak += ((1.0 / (range / peak)) * 10.0);
++      }
++
++      /* recall port */
++      current = AGS_LINE_MEMBER(list->data)->recall_port;
++
++      /* recall port - read value */
++      g_value_init(&value, G_TYPE_FLOAT);
++      ags_port_safe_read(current,
++			 &value);
++      
++      peak = g_value_get_float(&value);
++      g_value_unset(&value);
++
++      /* calculate peak */
++      if(range == 0.0 ||
++	 current->port_value_type == G_TYPE_BOOLEAN){
++	if(peak != 0.0){
++	  average_peak = 10.0;
++	}
++      }else{
++	average_peak += ((1.0 / (range / peak)) * 10.0);
++      }
++      
++      /* apply */
++      if(AGS_IS_LED(child)){
++	if(average_peak != 0.0){
++	  ags_led_set_active(child);
++	}
++      }else{
++	g_object_get(child,
++		     "adjustment\0", &adjustment,
++		     NULL);
++	
++	gtk_adjustment_set_value(adjustment,
++				 average_peak);
++      }
++    }
++    
++    list = list->next;
++  }
++
++  g_list_free(list_start);
++
++  /* unlock gdk threads */
++  gdk_threads_leave();
+ }
diff --git a/debian/patches/wish-effect-line-callbacks-h.patch b/debian/patches/wish-effect-line-callbacks-h.patch
new file mode 100644
index 0000000..b33382c
--- /dev/null
+++ b/debian/patches/wish-effect-line-callbacks-h.patch
@@ -0,0 +1,16 @@
+Description: This is a wishlist patch. It provides the function declaration of
+ the update functionality of output widgets.
+ This widget is currently used by AgsFFPlayer and AgsSynth.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_effect_line_callbacks.h
++++ b/ags/X/ags_effect_line_callbacks.h
+@@ -38,4 +38,7 @@
+ 					    guint nth,
+ 					    AgsEffectLine *effect_line);
+ 
++void ags_effect_line_output_port_run_post_callback(AgsRecall *recall,
++						   AgsEffectLine *effect_line);
++
+ #endif /*__AGS_EFFECT_LINE_CALLBACKS_H__*/
diff --git a/debian/patches/wish-effect-line-h.patch b/debian/patches/wish-effect-line-h.patch
new file mode 100644
index 0000000..7b98604
--- /dev/null
+++ b/debian/patches/wish-effect-line-h.patch
@@ -0,0 +1,26 @@
+Description: This is a wishlist patch. It provides the declaration of redrawing
+ function of output widgets.
+ This widget is currently used by AgsFFPlayer and AgsSynth.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_effect_line.h
++++ b/ags/X/ags_effect_line.h
+@@ -63,6 +63,8 @@
+   GtkLabel *label;
+   
+   GtkTable *table;
++
++  GList *queued_drawing;
+ };
+ 
+ struct _AgsEffectLineClass
+@@ -98,6 +100,8 @@
+ 				guint output_pad_start);
+ GList* ags_effect_line_find_port(AgsEffectLine *effect_line);
+ 
++gboolean ags_effect_line_indicator_queue_draw_timeout(GtkWidget *widget);
++
+ AgsEffectLine* ags_effect_line_new(AgsChannel *channel);
+ 
+ #endif /*__AGS_EFFECT_LINE_H__*/
diff --git a/debian/patches/wish-hindicator.patch b/debian/patches/wish-hindicator.patch
new file mode 100644
index 0000000..2090b5d
--- /dev/null
+++ b/debian/patches/wish-hindicator.patch
@@ -0,0 +1,180 @@
+Description: This is a wishlist patch. It implements the drawing primitives of
+ the horizontal indicator widget.
+ It is used by output configurations and defaulted for AgsLadpsaBridge,
+ AgsDssiBridge and AgsLv2Bridge.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/widget/ags_hindicator.c
++++ b/ags/widget/ags_hindicator.c
+@@ -23,7 +23,25 @@
+ void ags_hindicator_init(AgsHIndicator *indicator);
+ void ags_hindicator_show(GtkWidget *widget);
+ 
++gboolean ags_hindicator_expose(GtkWidget *widget,
++			       GdkEventExpose *event);
++gboolean ags_hindicator_configure(GtkWidget *widget,
++				  GdkEventConfigure *event);
++
++void ags_hindicator_draw(AgsHIndicator *indicator);
++
++/**
++ * SECTION:ags_hindicator
++ * @short_description: A horizontal indicator widget
++ * @title: AgsHIndicator
++ * @section_id:
++ * @include: ags/widget/ags_hindicator.h
++ *
++ * #AgsHIndicator is a widget visualizing a #GtkAdjustment.
++ */
++
+ static gpointer ags_hindicator_parent_class = NULL;
++GtkStyle *indicator_style;
+ 
+ GType
+ ags_hindicator_get_type(void)
+@@ -57,22 +75,141 @@
+   GtkWidgetClass *widget;
+ 
+   ags_hindicator_parent_class = g_type_class_peek_parent(indicator);
++
++  /* GtkWidgetClass */
++  widget = (GtkWidgetClass *) indicator;
++
++  widget->expose_event = ags_hindicator_expose;
++  widget->configure_event = ags_hindicator_configure;
+ }
+ 
+ void
+ ags_hindicator_init(AgsHIndicator *indicator)
+ {
+-  g_object_set(G_OBJECT(indicator),
+-	       "app-paintable\0", TRUE,
+-	       NULL);
++  gtk_widget_set_size_request((GtkWidget *) indicator,
++			      100,
++			      16);
++}
++gboolean
++ags_hindicator_configure(GtkWidget *widget,
++			 GdkEventConfigure *event)
++{
++  ags_hindicator_draw((AgsHIndicator *) widget);
++
++  return(FALSE);
++}
++
++gboolean
++ags_hindicator_expose(GtkWidget *widget,
++		     GdkEventExpose *event)
++{
++  ags_hindicator_draw((AgsHIndicator *) widget);
++
++  return(FALSE);
++}
++
++void
++ags_hindicator_draw(AgsHIndicator *indicator)
++{
++  GtkWidget *widget;
++  
++  GtkAdjustment *adjustment;
++  GtkStyle *indicator_style;
++  cairo_t *cr;
++  
++  gdouble value;
++  guint width, height;
++  guint segment_width, segment_height;
++  guint padding;
++  guint i;
++
++  static const gdouble white_gc = 65535.0;
++
++  widget = GTK_WIDGET(indicator);
++  indicator_style = gtk_widget_get_style(widget);
++  
++  adjustment = AGS_INDICATOR(indicator)->adjustment;
++
++  if(adjustment == NULL){
++    return;
++  }
++  //  g_message("draw %f\0", adjustment->value);
++
++  cr = gdk_cairo_create(widget->window);
++
++  if(cr == NULL){
++    return;
++  }
++  
++  width = 100;
++  height = 16;
++
++  segment_width = 7;
++  segment_height = height;
++
++  padding = 3;
++
++  cairo_surface_flush(cairo_get_target(cr));
++  cairo_push_group(cr);
++
++  for(i = 0; i < width / (segment_width + padding); i++){
++    if(adjustment->value > 0.0 &&
++       (1.0 / adjustment->value * i < (width / (segment_width + padding)))){
++      /* active */
++      cairo_set_source_rgb(cr,
++			   indicator_style->light[0].red / white_gc,
++			   indicator_style->light[0].green / white_gc,
++			   indicator_style->light[0].blue / white_gc);
++    }else{
++      /* normal */
++      cairo_set_source_rgb(cr,
++			   indicator_style->dark[0].red / white_gc,
++			   indicator_style->dark[0].green / white_gc,
++			   indicator_style->dark[0].blue / white_gc);
++    }
++
++    cairo_rectangle(cr,
++		    width - i * (segment_width + padding) - segment_width, 0,
++		    segment_width, segment_height);
++    cairo_fill(cr);
++
++    /* outline */
++    cairo_set_source_rgb(cr,
++			 indicator_style->fg[0].red / white_gc,
++			 indicator_style->fg[0].green / white_gc,
++			 indicator_style->fg[0].blue / white_gc);
++    cairo_rectangle(cr,
++		    width - i * (segment_width + padding) - segment_width, 0,
++		    segment_width, segment_height);
++    cairo_stroke(cr);
++  }
++
++  cairo_pop_group_to_source(cr);
++  cairo_paint(cr);
++
++  cairo_surface_mark_dirty(cairo_get_target(cr));
++  cairo_destroy(cr);
+ }
+ 
++/**
++ * ags_hindicator_new:
++ *
++ * Creates an #AgsHIndicator.
++ *
++ * Returns: a new #AgsHIndicator
++ *
++ * Since: 0.7.128
++ */
+ AgsHIndicator*
+ ags_hindicator_new()
+ {
+   AgsHIndicator *indicator;
++  GtkAdjustment *adjustment;
++
++  adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 0.1, 0.1, 0.0);
+ 
+   indicator = (AgsHIndicator *) g_object_new(AGS_TYPE_HINDICATOR,
++					     "adjustment\0", adjustment,
+ 					     NULL);
+   
+   return(indicator);
diff --git a/debian/patches/wish-ladspa-browser-c.patch b/debian/patches/wish-ladspa-browser-c.patch
new file mode 100644
index 0000000..6f77e80
--- /dev/null
+++ b/debian/patches/wish-ladspa-browser-c.patch
@@ -0,0 +1,67 @@
+Description: This is a wishlist patch. It lets you configure the output widget
+ of plugins like LADSPA.
+ It is used by AgsMixer, AgsDrum, AgsFFPlayer and AgsSynth.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_ladspa_browser.c
++++ b/ags/X/ags_ladspa_browser.c
+@@ -357,6 +357,58 @@
+ }
+ 
+ /**
++ * ags_ladspa_browser_combo_box_output_boolean_controls_new:
++ *
++ * Creates a #GtkComboBox containing suitable widgets as controls.
++ *
++ * Returns: a new #GtkComboBox
++ *
++ * Since: 0.7.128
++ */
++GtkWidget*
++ags_ladspa_browser_combo_box_output_boolean_controls_new()
++{
++  GtkComboBoxText *combo_box;
++
++  combo_box = (GtkComboBoxText *) gtk_combo_box_text_new();
++
++  gtk_combo_box_text_append_text(combo_box,
++				 "led\0");
++
++  gtk_combo_box_set_active((GtkComboBox *) combo_box,
++			   1);
++
++  return((GtkWidget *) combo_box);
++}
++
++/**
++ * ags_ladspa_browser_combo_box_controls_new:
++ *
++ * Creates a #GtkComboBox containing suitable widgets as controls.
++ *
++ * Returns: a new #GtkComboBox
++ *
++ * Since: 0.7.128
++ */
++GtkWidget*
++ags_ladspa_browser_combo_box_output_controls_new()
++{
++  GtkComboBoxText *combo_box;
++
++  combo_box = (GtkComboBoxText *) gtk_combo_box_text_new();
++
++  gtk_combo_box_text_append_text(combo_box,
++				 "vertical indicator\0");
++  gtk_combo_box_text_append_text(combo_box,
++				 "horizontal indicator\0");
++
++  gtk_combo_box_set_active((GtkComboBox *) combo_box,
++			   1);
++
++  return((GtkWidget *) combo_box);
++}
++
++/**
+  * ags_ladspa_browser_combo_box_boolean_controls_new:
+  *
+  * Creates a #GtkComboBox containing suitable widgets as controls.
diff --git a/debian/patches/wish-ladspa-browser-callbacks.patch b/debian/patches/wish-ladspa-browser-callbacks.patch
new file mode 100644
index 0000000..ec6543b
--- /dev/null
+++ b/debian/patches/wish-ladspa-browser-callbacks.patch
@@ -0,0 +1,46 @@
+Description: This is a wishlist patch. It distinguishes between input and
+ output widgets as showing the port configuration.
+ It is used by AgsMixer, AgsDrum, AgsFFPlayer and AgsSynth.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_ladspa_browser_callbacks.c
++++ b/ags/X/ags_ladspa_browser_callbacks.c
+@@ -180,15 +180,29 @@
+ 				  y, y + 1);
+ 
+ 	if(LADSPA_IS_HINT_TOGGLED(plugin_descriptor->PortRangeHints[i].HintDescriptor)){
+-	  gtk_table_attach_defaults(table,
+-				    GTK_WIDGET(ags_ladspa_browser_combo_box_boolean_controls_new()),
+-				    1, 2,
+-				    y, y + 1);
++	  if(LADSPA_IS_PORT_OUTPUT(port_descriptor[i])){
++	    gtk_table_attach_defaults(table,
++				      GTK_WIDGET(ags_ladspa_browser_combo_box_output_boolean_controls_new()),
++				      1, 2,
++				      y, y + 1);
++	  }else{
++	    gtk_table_attach_defaults(table,
++				      GTK_WIDGET(ags_ladspa_browser_combo_box_boolean_controls_new()),
++				      1, 2,
++				      y, y + 1);
++	  }
+ 	}else{
+-	  gtk_table_attach_defaults(table,
+-				    GTK_WIDGET(ags_ladspa_browser_combo_box_controls_new()),
+-				    1, 2,
+-				    y, y + 1);
++	  if(LADSPA_IS_PORT_OUTPUT(port_descriptor[i])){
++	    gtk_table_attach_defaults(table,
++				      GTK_WIDGET(ags_ladspa_browser_combo_box_output_controls_new()),
++				      1, 2,
++				      y, y + 1);
++	  }else{
++	    gtk_table_attach_defaults(table,
++				      GTK_WIDGET(ags_ladspa_browser_combo_box_controls_new()),
++				      1, 2,
++				      y, y + 1);
++	  }
+ 	}
+ 	
+ 	y++;
diff --git a/debian/patches/wish-ladspa-browser-h.patch b/debian/patches/wish-ladspa-browser-h.patch
new file mode 100644
index 0000000..09f995f
--- /dev/null
+++ b/debian/patches/wish-ladspa-browser-h.patch
@@ -0,0 +1,21 @@
+Description: This is a wishlist patch. It declares the functions to configure
+ the output widget of plugins like LADSPA.
+ It is used by AgsMixer, AgsDrum, AgsFFPlayer and AgsSynth.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_ladspa_browser.h
++++ b/ags/X/ags_ladspa_browser.h
+@@ -56,8 +56,12 @@
+ gchar* ags_ladspa_browser_get_plugin_filename(AgsLadspaBrowser *ladspa_browser);
+ gchar* ags_ladspa_browser_get_plugin_effect(AgsLadspaBrowser *ladspa_browser);
+ 
++GtkWidget* ags_ladspa_browser_combo_box_output_boolean_controls_new();
++GtkWidget* ags_ladspa_browser_combo_box_output_controls_new();
++
+ GtkWidget* ags_ladspa_browser_combo_box_boolean_controls_new();
+ GtkWidget* ags_ladspa_browser_combo_box_controls_new();
++
+ GtkWidget* ags_ladspa_browser_preview_new();
+ 
+ AgsLadspaBrowser* ags_ladspa_browser_new();
diff --git a/debian/patches/wish-line-c.patch b/debian/patches/wish-line-c.patch
new file mode 100644
index 0000000..9f5437a
--- /dev/null
+++ b/debian/patches/wish-line-c.patch
@@ -0,0 +1,381 @@
+Description: This is a wishlist patch. It modifies the recall callback handler
+ to use the generic callback ags_line_output_port_run_post_callback().
+ This is used by AgsSynthInputLine, AgsDrumInputLine and AgsMixerInputLine.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_line.c
++++ b/ags/X/ags_line.c
+@@ -43,11 +43,15 @@
+ #include <ags/audio/ags_channel.h>
+ #include <ags/audio/ags_output.h>
+ #include <ags/audio/ags_input.h>
++#include <ags/audio/ags_recall_container.h>
+ #include <ags/audio/ags_recall_ladspa.h>
+ #include <ags/audio/ags_recall_lv2.h>
+ 
+ #include <ags/audio/recall/ags_peak_channel_run.h>
+ 
++#include <ags/widget/ags_led.h>
++#include <ags/widget/ags_vindicator.h>
++#include <ags/widget/ags_hindicator.h>
+ #include <ags/widget/ags_dial.h>
+ 
+ #include <ags/X/ags_window.h>
+@@ -128,7 +132,7 @@
+ static gpointer ags_line_parent_class = NULL;
+ static guint line_signals[LAST_SIGNAL];
+ 
+-GHashTable *ags_indicator_queue_draw = NULL;
++GHashTable *ags_line_indicator_queue_draw = NULL;
+ 
+ GType
+ ags_line_get_type(void)
+@@ -385,8 +389,8 @@
+ void
+ ags_line_init(AgsLine *line)
+ {
+-  if(ags_indicator_queue_draw == NULL){
+-    ags_indicator_queue_draw = g_hash_table_new_full(g_direct_hash, g_direct_equal,
++  if(ags_line_indicator_queue_draw == NULL){
++    ags_line_indicator_queue_draw = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+ 						     NULL,
+ 						     NULL);
+   }
+@@ -436,14 +440,27 @@
+ ags_line_finalize(GObject *gobject)
+ {
+   AgsLine *line;
+-
+-  line = AGS_LINE(gobject);
++  GList *list;
+   
++  line = AGS_LINE(gobject);
++
++  /* remove indicator widget */
+   if(line->indicator != NULL){
+-    g_hash_table_remove(ags_indicator_queue_draw,
++    g_hash_table_remove(ags_line_indicator_queue_draw,
+ 			line->indicator);
+   }
+-  
++
++  /* remove of the queued drawing hash */
++  list = line->queued_drawing;
++
++  while(list != NULL){
++    g_hash_table_remove(ags_line_indicator_queue_draw,
++			list->data);
++
++    list = list->next;
++  }
++
++  /* call parent */
+   G_OBJECT_CLASS(ags_line_parent_class)->finalize(gobject);
+ }
+ 
+@@ -743,6 +760,8 @@
+   AgsLineMember *line_member;
+   GtkAdjustment *adjustment;
+ 
++  AgsRecallHandler *recall_handler;
++
+   AgsLadspaPlugin *ladspa_plugin;
+ 
+   AgsMutexManager *mutex_manager;
+@@ -754,11 +773,17 @@
+ 
+   gdouble step;
+   guint port_count;
++  gboolean has_output_port;
++
+   guint x, y;
+   guint k;
+ 
+   pthread_mutex_t *application_mutex;
+   pthread_mutex_t *channel_mutex;
++
++  /* get mutex manager and application mutex */
++  mutex_manager = ags_mutex_manager_get_instance();
++  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
+   
+   /* load plugin */
+   ladspa_plugin = ags_ladspa_manager_find_ladspa_plugin(ags_ladspa_manager_get_instance(),
+@@ -778,10 +803,6 @@
+     list = list->next;
+   }
+ 
+-  /* get mutex manager and application mutex */
+-  mutex_manager = ags_mutex_manager_get_instance();
+-  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
+-
+   /* get channel mutex */
+   pthread_mutex_lock(application_mutex);
+ 
+@@ -790,18 +811,49 @@
+   
+   pthread_mutex_unlock(application_mutex);
+   
+-  /* find ports */
++  /* play - find ports */
+   pthread_mutex_lock(channel_mutex);
+   
+   recall_start =
+     recall = ags_recall_get_by_effect(line->channel->play,
+ 				      filename,
+ 				      effect);
++  
++  if(recall == NULL){
++    pthread_mutex_unlock(channel_mutex);
++    
++    return(NULL);
++  }
++
+   recall = g_list_last(recall);
+   port = AGS_RECALL(recall->data)->port;
+ 
+   g_list_free(recall_start);
+ 
++  /* check has output port */
++  if((AGS_RECALL_HAS_OUTPUT_PORT & (AGS_RECALL(recall->data)->flags)) != 0){
++    has_output_port = TRUE;
++  }else{
++    has_output_port = FALSE;
++  }
++
++  /* recall handler of output port */
++  if(has_output_port){
++    AgsRecall *recall_channel_run_dummy;
++
++    recall_channel_run_dummy = ags_recall_find_template(AGS_RECALL_CONTAINER(AGS_RECALL(recall->data)->container)->recall_channel_run);
++    
++    /* alloc handler */
++    recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
++
++    recall_handler->signal_name = "run-post\0";
++    recall_handler->callback = G_CALLBACK(ags_line_output_port_run_post_callback);
++    recall_handler->data = (gpointer) line;
++
++    ags_recall_add_handler(AGS_RECALL(recall_channel_run_dummy), recall_handler);
++  }
++  
++  /* recall - find ports */
+   recall_start = 
+     recall = ags_recall_get_by_effect(line->channel->recall,
+ 				      filename,
+@@ -812,13 +864,29 @@
+   g_list_free(recall_start);
+ 
+   pthread_mutex_unlock(channel_mutex);
++
++  /* recall handler of output port */
++  if(has_output_port){
++    AgsRecall *recall_channel_run_dummy;
++
++    recall_channel_run_dummy = ags_recall_find_template(AGS_RECALL_CONTAINER(AGS_RECALL(recall->data)->container)->recall_channel_run);
++    
++    /* alloc handler */
++    recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
++
++    recall_handler->signal_name = "run-post\0";
++    recall_handler->callback = G_CALLBACK(ags_line_output_port_run_post_callback);
++    recall_handler->data = (gpointer) line;
++
++    ags_recall_add_handler(AGS_RECALL(recall_channel_run_dummy), recall_handler);
++  }
+   
+   /* load ports */
+   port_descriptor = AGS_BASE_PLUGIN(ladspa_plugin)->port;
+ 
+   port_count = g_list_length(port_descriptor);
+   k = 0;
+-
++  
+   while(port_descriptor != NULL){
+     if((AGS_PORT_DESCRIPTOR_CONTROL & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
+       GtkWidget *child_widget;
+@@ -830,9 +898,17 @@
+       guint step_count;
+       
+       if((AGS_PORT_DESCRIPTOR_TOGGLED & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
+-	widget_type = GTK_TYPE_TOGGLE_BUTTON;
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  widget_type = AGS_TYPE_LED;
++	}else{
++	  widget_type = GTK_TYPE_TOGGLE_BUTTON;
++	}
+       }else{
+-	widget_type = AGS_TYPE_DIAL;
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  widget_type = AGS_TYPE_HINDICATOR;
++	}else{
++	  widget_type = AGS_TYPE_DIAL;
++	}
+       }
+ 
+       if(control_type_name != NULL){
+@@ -943,8 +1019,15 @@
+ 				 upper_bound);
+ 	gtk_adjustment_set_value(adjustment,
+ 				 g_value_get_float(AGS_PORT_DESCRIPTOR(port_descriptor->data)->default_value));
++      }else if(AGS_IS_INDICATOR(child_widget) ||
++	       AGS_IS_LED(child_widget)){
++	g_hash_table_insert(ags_line_indicator_queue_draw,
++			    child_widget, ags_line_indicator_queue_draw_timeout);
++	line->queued_drawing = g_list_prepend(line->queued_drawing,
++					      child_widget);
++	g_timeout_add(1000 / 30, (GSourceFunc) ags_line_indicator_queue_draw_timeout, (gpointer) child_widget);
+       }
+-
++      
+ #ifdef AGS_DEBUG
+       g_message("ladspa bounds: %f %f\0", lower_bound, upper_bound);
+ #endif
+@@ -977,6 +1060,8 @@
+   AgsLineMember *line_member;
+   GtkAdjustment *adjustment;
+ 
++  AgsRecallHandler *recall_handler;
++
+   AgsLv2Plugin *lv2_plugin;
+ 
+   AgsMutexManager *mutex_manager;
+@@ -991,12 +1076,18 @@
+ 
+   gdouble step;
+   guint port_count;
++  gboolean has_output_port;
++
+   guint x, y;
+   guint k;
+   
+   pthread_mutex_t *application_mutex;
+   pthread_mutex_t *channel_mutex;
+ 
++  /* get mutex manager and application mutex */
++  mutex_manager = ags_mutex_manager_get_instance();
++  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
++
+   /* load plugin */
+   lv2_plugin = ags_lv2_manager_find_lv2_plugin(ags_lv2_manager_get_instance(),
+ 					       filename, effect);
+@@ -1015,10 +1106,6 @@
+     list = list->next;
+   }
+ 
+-  /* get mutex manager and application mutex */
+-  mutex_manager = ags_mutex_manager_get_instance();
+-  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
+-
+   /* get channel mutex */
+   pthread_mutex_lock(application_mutex);
+ 
+@@ -1027,7 +1114,7 @@
+   
+   pthread_mutex_unlock(application_mutex);
+   
+-  /* find ports */
++  /* play - find ports */
+   pthread_mutex_lock(channel_mutex);
+   
+   recall_start =
+@@ -1046,6 +1133,30 @@
+ 
+   g_list_free(recall_start);
+ 
++  /* check has output port */
++  if((AGS_RECALL_HAS_OUTPUT_PORT & (AGS_RECALL(recall->data)->flags)) != 0){
++    has_output_port = TRUE;
++  }else{
++    has_output_port = FALSE;
++  }
++
++  /* recall handler of output port */
++  if(has_output_port){
++    AgsRecall *recall_channel_run_dummy;
++
++    recall_channel_run_dummy = ags_recall_find_template(AGS_RECALL_CONTAINER(AGS_RECALL(recall->data)->container)->recall_channel_run)->data;
++    
++    /* alloc handler */
++    recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
++
++    recall_handler->signal_name = "run-post\0";
++    recall_handler->callback = G_CALLBACK(ags_line_output_port_run_post_callback);
++    recall_handler->data = (gpointer) line;
++
++    ags_recall_add_handler(AGS_RECALL(recall_channel_run_dummy), recall_handler);
++  }
++
++  /* recall - find ports */
+   recall_start = 
+     recall = ags_recall_get_by_effect(line->channel->recall,
+ 				      filename,
+@@ -1055,8 +1166,24 @@
+   recall_port = AGS_RECALL(recall->data)->port;
+   g_list_free(recall_start);
+ 
+-  pthread_mutex_unlock(channel_mutex);
+-  
++  pthread_mutex_unlock(channel_mutex);  
++
++  /* recall handler of output port */
++  if(has_output_port){
++    AgsRecall *recall_channel_run_dummy;
++
++    recall_channel_run_dummy = ags_recall_find_template(AGS_RECALL_CONTAINER(AGS_RECALL(recall->data)->container)->recall_channel_run)->data;
++    
++    /* alloc handler */
++    recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
++
++    recall_handler->signal_name = "run-post\0";
++    recall_handler->callback = G_CALLBACK(ags_line_output_port_run_post_callback);
++    recall_handler->data = (gpointer) line;
++
++    ags_recall_add_handler(AGS_RECALL(recall_channel_run_dummy), recall_handler);
++  }
++
+   /* load ports */
+   port_descriptor = AGS_BASE_PLUGIN(lv2_plugin)->port;
+ 
+@@ -1075,9 +1202,17 @@
+       guint step_count;
+       
+       if((AGS_PORT_DESCRIPTOR_TOGGLED & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
+-	widget_type = GTK_TYPE_TOGGLE_BUTTON;
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  widget_type = AGS_TYPE_LED;
++	}else{
++	  widget_type = GTK_TYPE_TOGGLE_BUTTON;
++	}
+       }else{
+-	widget_type = AGS_TYPE_DIAL;
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  widget_type = AGS_TYPE_HINDICATOR;
++	}else{
++	  widget_type = AGS_TYPE_DIAL;
++	}
+       }
+ 
+       if(control_type_name != NULL){
+@@ -1163,6 +1298,12 @@
+ 				 upper_bound);
+ 	gtk_adjustment_set_value(adjustment,
+ 				 g_value_get_float(AGS_PORT_DESCRIPTOR(port_descriptor->data)->default_value));
++      }else if(AGS_IS_INDICATOR(child_widget)){
++	g_hash_table_insert(ags_line_indicator_queue_draw,
++			    child_widget, ags_line_indicator_queue_draw_timeout);
++	line->queued_drawing = g_list_prepend(line->queued_drawing,
++					      child_widget);
++	g_timeout_add(1000 / 30, (GSourceFunc) ags_line_indicator_queue_draw_timeout, (gpointer) child_widget);
+       }
+ 
+ #ifdef AGS_DEBUG
+@@ -1544,7 +1685,7 @@
+ gboolean
+ ags_line_indicator_queue_draw_timeout(GtkWidget *widget)
+ {
+-  if(g_hash_table_lookup(ags_indicator_queue_draw,
++  if(g_hash_table_lookup(ags_line_indicator_queue_draw,
+ 			 widget) != NULL){
+     gtk_widget_queue_draw(widget);
+     
diff --git a/debian/patches/wish-line-callbacks-c.patch b/debian/patches/wish-line-callbacks-c.patch
new file mode 100644
index 0000000..d3c7f15
--- /dev/null
+++ b/debian/patches/wish-line-callbacks-c.patch
@@ -0,0 +1,307 @@
+Description: This is a wishlist patch. It provides the callback function
+ ags_line_output_port_run_post_callback() updating the controls value.
+ AgsLine is used by AgsSynthInputLine, AgsMixerInputLine and AgsDrumInputLine.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_line_callbacks.c
++++ b/ags/X/ags_line_callbacks.c
+@@ -23,7 +23,8 @@
+ #include <ags/object/ags_soundcard.h>
+ 
+ #include <ags/thread/ags_mutex_manager.h>
+-#include <ags/thread/ags_task_thread.h>
++
++#include <ags/plugin/ags_base_plugin.h>
+ 
+ #include <ags/audio/ags_playback.h>
+ #include <ags/audio/ags_recall.h>
+@@ -41,8 +42,10 @@
+ #include <ags/audio/recall/ags_copy_pattern_channel.h>
+ #include <ags/audio/recall/ags_copy_pattern_channel_run.h>
+ 
++#include <ags/widget/ags_led.h>
+ #include <ags/widget/ags_indicator.h>
+ #include <ags/widget/ags_vindicator.h>
++#include <ags/widget/ags_hindicator.h>
+ 
+ #include <ags/X/ags_window.h>
+ #include <ags/X/ags_machine.h>
+@@ -58,8 +61,6 @@
+ #include <ags/X/ags_dssi_browser.h>
+ #include <ags/X/ags_lv2_browser.h>
+ 
+-#include <ags/X/task/ags_change_indicator.h>
+-
+ int
+ ags_line_parent_set_callback(GtkWidget *widget, GtkObject *old_parent, AgsLine *line)
+ {
+@@ -231,8 +232,23 @@
+ 	      controls = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(port_control->data));
+ 
+ 	      if(!g_ascii_strncasecmp(controls,
+-				      "spin button\0",
+-				      12)){
++				      "led\0",
++				      4)){
++		control_type_name = g_list_prepend(control_type_name,
++						   "AgsLed\0");
++	      }else if(!g_ascii_strncasecmp(controls,
++					    "vertical indicator\0",
++					    19)){
++		control_type_name = g_list_prepend(control_type_name,
++						   "AgsVIndicator\0");
++	      }else if(!g_ascii_strncasecmp(controls,
++					    "horizontal indicator\0",
++					    19)){
++		control_type_name = g_list_prepend(control_type_name,
++						   "AgsHIndicator\0");
++	      }else if(!g_ascii_strncasecmp(controls,
++					    "spin button\0",
++					    12)){
+ 		control_type_name = g_list_prepend(control_type_name,
+ 						   "GtkSpinButton\0");
+ 	      }else if(!g_ascii_strncasecmp(controls,
+@@ -268,8 +284,8 @@
+ 	  }
+ 
+ 	  /* free lists */
+-	g_list_free(description_start);
+-	g_list_free(port_control_start);
++	  g_list_free(description_start);
++	  g_list_free(port_control_start);
+ 	}
+       }
+       
+@@ -339,72 +355,124 @@
+ }
+ 
+ void
+-ags_line_peak_run_post_callback(AgsRecall *peak_channel_run,
+-				AgsLine *line)
++ags_line_output_port_run_post_callback(AgsRecall *recall,
++				       AgsLine *line)
+ {
+   GtkWidget *child;
+ 
+-  AgsPort *port;
+-
+-  AgsMutexManager *mutex_manager;
+-  AgsTaskThread *task_thread;
+-
+   GList *list, *list_start;
+-
+-  gdouble peak;
+-
+-  GValue value = {0,};
+-
+-  pthread_mutex_t *application_mutex;
+-  pthread_mutex_t *channel_mutex;
+-
++  
+   /* lock gdk threads */
+   gdk_threads_enter();
+-
+-  mutex_manager = ags_mutex_manager_get_instance();
+-  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
+   
+   list_start = 
+     list = gtk_container_get_children((GtkContainer *) AGS_LINE(line)->expander->table);
+ 
++  /* check members */
+   while(list != NULL){
+     if(AGS_IS_LINE_MEMBER(list->data) &&
+-       AGS_LINE_MEMBER(list->data)->widget_type == AGS_TYPE_VINDICATOR){
++       (AGS_LINE_MEMBER(list->data)->widget_type == AGS_TYPE_VINDICATOR ||
++	AGS_LINE_MEMBER(list->data)->widget_type == AGS_TYPE_HINDICATOR ||
++	AGS_LINE_MEMBER(list->data)->widget_type == AGS_TYPE_LED)){
+       GtkAdjustment *adjustment;
+ 
+-      child = GTK_BIN(list->data)->child;
++      AgsPort *current;
++	
++      gdouble average_peak;
++      gdouble lower, upper;
++      gdouble range;
++      gdouble peak;
+ 
+-      /* get port */
+-      pthread_mutex_lock(application_mutex);
++      GValue value = {0,};
+ 
+-      channel_mutex = ags_mutex_manager_lookup(mutex_manager,
+-					       (GObject *) line->channel);
++      child = GTK_BIN(list->data)->child;
++      
++      average_peak = 0.0;
+       
+-      pthread_mutex_unlock(application_mutex);
++      /* play port */
++      current = AGS_LINE_MEMBER(list->data)->port;
+ 
+-      pthread_mutex_lock(channel_mutex);
++      if(current == NULL){
++	list = list->next;
++	
++	continue;
++      }
++	
++      /* check if output port and specifier matches */
++      pthread_mutex_lock(current->mutex);
+       
+-      port = AGS_PEAK_CHANNEL(AGS_RECALL_CHANNEL_RUN(peak_channel_run)->recall_channel)->peak;
++      if((AGS_PORT_IS_OUTPUT & (current->flags)) == 0 ||
++	 current->port_descriptor == NULL ||
++	 g_ascii_strcasecmp(current->specifier,
++			    AGS_LINE_MEMBER(list->data)->specifier)){
++	pthread_mutex_unlock(current->mutex);
++	
++	list = list->next;
++	
++	continue;
++      }
++
++      /* lower and upper */
++      lower = g_value_get_float(AGS_PORT_DESCRIPTOR(current->port_descriptor)->lower_value);
++      upper = g_value_get_float(AGS_PORT_DESCRIPTOR(current->port_descriptor)->upper_value);
++      
++      pthread_mutex_unlock(current->mutex);
+ 
+-      pthread_mutex_unlock(channel_mutex);
++      /* get range */
++      range = upper - lower;
+ 
+-      /* get peak */
+-      g_value_init(&value, G_TYPE_DOUBLE);
+-      ags_port_safe_read(port,
++      /* play port - read value */
++      g_value_init(&value, G_TYPE_FLOAT);
++      ags_port_safe_read(current,
+ 			 &value);
+-
+-      peak = g_value_get_double(&value);
++      
++      peak = g_value_get_float(&value);
+       g_value_unset(&value);
+ 
+-      /* apply */
+-      g_object_get(child,
+-		   "adjustment\0", &adjustment,
+-		   NULL);
++      /* calculate peak */
++      if(range == 0.0 ||
++	 current->port_value_type == G_TYPE_BOOLEAN){
++	if(peak != 0.0){
++	  average_peak = 10.0;
++	}
++      }else{
++	average_peak += ((1.0 / (range / peak)) * 10.0);
++      }
+ 
+-      gtk_adjustment_set_value(adjustment,
+-			       peak);
++      /* recall port */
++      current = AGS_LINE_MEMBER(list->data)->recall_port;
+ 
+-      break;
++      /* recall port - read value */
++      g_value_init(&value, G_TYPE_FLOAT);
++      ags_port_safe_read(current,
++			 &value);
++      
++      peak = g_value_get_float(&value);
++      g_value_unset(&value);
++
++      /* calculate peak */
++      if(range == 0.0 ||
++	 current->port_value_type == G_TYPE_BOOLEAN){
++	if(peak != 0.0){
++	  average_peak = 10.0;
++	}
++      }else{
++	average_peak += ((1.0 / (range / peak)) * 10.0);
++      }
++      
++      /* apply */
++      if(AGS_IS_LED(child)){
++	if(average_peak != 0.0){
++	  ags_led_set_active(child);
++	}
++      }else{
++	g_object_get(child,
++		     "adjustment\0", &adjustment,
++		     NULL);
++	
++	gtk_adjustment_set_value(adjustment,
++				 average_peak);
++      }
+     }
+     
+     list = list->next;
+@@ -423,27 +491,63 @@
+   AgsChannel *channel;
+   AgsPlayback *playback;
+   AgsChannel *next_pad;
++  AgsRecallID *match_recall_id;
++
++  AgsMutexManager *mutex_manager;
+ 
+   gboolean all_done;
+ 
++  pthread_mutex_t *application_mutex;
++  pthread_mutex_t *channel_mutex;
++
++  mutex_manager = ags_mutex_manager_get_instance();
++  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
++
+   gdk_threads_enter();
+   
++  /* retrieve channel */
+   channel = AGS_PAD(AGS_LINE(line)->pad)->channel;
++
++  /* retrieve channel mutex */
++  pthread_mutex_lock(application_mutex);
++
++  channel_mutex = ags_mutex_manager_lookup(mutex_manager,
++					   (GObject *) channel);
++
++  pthread_mutex_unlock(application_mutex);
++
++  /* get next pad */
++  pthread_mutex_lock(channel_mutex);
++
+   next_pad = channel->next_pad;
+ 
++  pthread_mutex_unlock(channel_mutex);
++
+   all_done = TRUE;
+ 
+   while(channel != next_pad){
++    pthread_mutex_lock(channel_mutex);
++
+     playback = AGS_PLAYBACK(channel->playback);
+-    
+-    if(playback->recall_id[0] != NULL){
++    match_recall_id = playback->recall_id[0];
++		
++    pthread_mutex_unlock(channel_mutex);
++
++    /* check if pending */
++    if(match_recall_id != NULL){
+       all_done = FALSE;
+       break;
+     }
+-    
++
++    /* iterate */
++    pthread_mutex_lock(channel_mutex);
++
+     channel = channel->next;
++
++    pthread_mutex_unlock(channel_mutex);
+   }
+ 
++  /* toggle play button if all playback done */
+   if(all_done){
+     AgsPad *pad;
+ 
diff --git a/debian/patches/wish-line-callbacks-h.patch b/debian/patches/wish-line-callbacks-h.patch
new file mode 100644
index 0000000..f235484
--- /dev/null
+++ b/debian/patches/wish-line-callbacks-h.patch
@@ -0,0 +1,19 @@
+Description: This is a wishlist patch. It declares the callback function
+ ags_line_output_port_run_post_callback() updating the controls value.
+ AgsLine is used by AgsSynthInputLine, AgsMixerInputLine and AgsDrumInputLine.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_line_callbacks.h
++++ b/ags/X/ags_line_callbacks.h
+@@ -45,8 +45,8 @@
+ 			      AgsLine *line);
+ 
+ /* AgsRecall - recall */
+-void ags_line_peak_run_post_callback(AgsRecall *peak_channel,
+-				     AgsLine *line);
++void ags_line_output_port_run_post_callback(AgsRecall *recall,
++					    AgsLine *line);
+ 
+ void ags_line_copy_pattern_done(AgsRecall *recall,
+ 				AgsLine *line);
diff --git a/debian/patches/wish-line-h.patch b/debian/patches/wish-line-h.patch
new file mode 100644
index 0000000..b9e7df1
--- /dev/null
+++ b/debian/patches/wish-line-h.patch
@@ -0,0 +1,17 @@
+Description: This is a wishlist patch. It extends the AgsLine struct in order
+ to proper redrawing of the output widget.
+ This is used by AgsSynthInputLine, AgsDrumInputLine and AgsMixerInputLine.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_line.h
++++ b/ags/X/ags_line.h
+@@ -72,6 +72,8 @@
+   AgsExpander *expander;
+ 
+   GtkWidget *indicator;
++
++  GList *queued_drawing;
+ };
+ 
+ struct _AgsLineClass
diff --git a/debian/patches/wish-line-member.patch b/debian/patches/wish-line-member.patch
new file mode 100644
index 0000000..02bfede
--- /dev/null
+++ b/debian/patches/wish-line-member.patch
@@ -0,0 +1,29 @@
+Description: This is a wishlist patch. It adds support for additional output
+ widget types.
+ AgsLineMember is used by AgsLine.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_line_member.c
++++ b/ags/X/ags_line_member.c
+@@ -32,6 +32,8 @@
+ 
+ #include <ags/audio/thread/ags_audio_loop.h>
+ 
++#include <ags/widget/ags_led.h>
++#include <ags/widget/ags_hindicator.h>
+ #include <ags/widget/ags_dial.h>
+ 
+ #include <ags/X/ags_window.h>
+@@ -553,7 +555,10 @@
+ 	gtk_toggle_button_set_active((GtkToggleButton *) new_child,
+ 				     active);
+       }else{
+-	g_warning("ags_line_member_set_property() - unknown child type %s\0", g_type_name(widget_type));
++	if(!(AGS_IS_INDICATOR(new_child) ||
++	     AGS_IS_LED(new_child))){
++	  g_warning("ags_line_member_set_property() - unknown child type %s\0", g_type_name(widget_type));
++	}
+       }
+ 
+       /* add */
diff --git a/debian/patches/wish-lv2-browser-c.patch b/debian/patches/wish-lv2-browser-c.patch
new file mode 100644
index 0000000..e4a73c7
--- /dev/null
+++ b/debian/patches/wish-lv2-browser-c.patch
@@ -0,0 +1,67 @@
+Description: This is a wishlist patch. It lets you configure the output widget
+ of plugins like Lv2.
+ It is used by AgsMixer, AgsDrum, AgsFFPlayer and AgsSynth.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_lv2_browser.c
++++ b/ags/X/ags_lv2_browser.c
+@@ -355,6 +355,58 @@
+ }
+ 
+ /**
++ * ags_lv2_browser_combo_box_output_boolean_controls_new:
++ *
++ * Creates a #GtkComboBox containing suitable widgets as controls.
++ *
++ * Returns: a new #GtkComboBox
++ *
++ * Since: 0.7.128
++ */
++GtkWidget*
++ags_lv2_browser_combo_box_output_boolean_controls_new()
++{
++  GtkComboBoxText *combo_box;
++
++  combo_box = (GtkComboBoxText *) gtk_combo_box_text_new();
++
++  gtk_combo_box_text_append_text(combo_box,
++				 "led\0");
++
++  gtk_combo_box_set_active((GtkComboBox *) combo_box,
++			   1);
++
++  return((GtkWidget *) combo_box);
++}
++
++/**
++ * ags_lv2_browser_combo_box_controls_new:
++ *
++ * Creates a #GtkComboBox containing suitable widgets as controls.
++ *
++ * Returns: a new #GtkComboBox
++ *
++ * Since: 0.7.128
++ */
++GtkWidget*
++ags_lv2_browser_combo_box_output_controls_new()
++{
++  GtkComboBoxText *combo_box;
++
++  combo_box = (GtkComboBoxText *) gtk_combo_box_text_new();
++
++  gtk_combo_box_text_append_text(combo_box,
++				 "vertical indicator\0");
++  gtk_combo_box_text_append_text(combo_box,
++				 "horizontal indicator\0");
++
++  gtk_combo_box_set_active((GtkComboBox *) combo_box,
++			   1);
++
++  return((GtkWidget *) combo_box);
++}
++
++/**
+  * ags_lv2_browser_combo_box_boolean_controls_new:
+  *
+  * Creates a #GtkComboBox containing suitable widgets as controls.
diff --git a/debian/patches/wish-lv2-browser-callbacks.patch b/debian/patches/wish-lv2-browser-callbacks.patch
new file mode 100644
index 0000000..7796146
--- /dev/null
+++ b/debian/patches/wish-lv2-browser-callbacks.patch
@@ -0,0 +1,46 @@
+Description: This is a wishlist patch. It distinguishes between input and
+ output widgets as showing the port configuration.
+ It is used by AgsMixer, AgsDrum, AgsFFPlayer and AgsSynth.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_lv2_browser_callbacks.c
++++ b/ags/X/ags_lv2_browser_callbacks.c
+@@ -160,15 +160,29 @@
+ 				y, y + 1);
+       
+       if((AGS_PORT_DESCRIPTOR_TOGGLED & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
+-	gtk_table_attach_defaults(table,
+-				  GTK_WIDGET(ags_lv2_browser_combo_box_boolean_controls_new()),
+-				  1, 2,
+-				  y, y + 1);
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  gtk_table_attach_defaults(table,
++				    GTK_WIDGET(ags_lv2_browser_combo_box_output_boolean_controls_new()),
++				    1, 2,
++				    y, y + 1);
++	}else{
++	  gtk_table_attach_defaults(table,
++				    GTK_WIDGET(ags_lv2_browser_combo_box_boolean_controls_new()),
++				    1, 2,
++				    y, y + 1);
++	}
+       }else{
+-	gtk_table_attach_defaults(table,
+-				  GTK_WIDGET(ags_lv2_browser_combo_box_controls_new()),
+-				  1, 2,
+-				  y, y + 1);
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  gtk_table_attach_defaults(table,
++				    GTK_WIDGET(ags_lv2_browser_combo_box_output_controls_new()),
++				    1, 2,
++				    y, y + 1);
++	}else{
++	  gtk_table_attach_defaults(table,
++				    GTK_WIDGET(ags_lv2_browser_combo_box_controls_new()),
++				    1, 2,
++				    y, y + 1);
++	}
+       }
+ 	
+       y++;
diff --git a/debian/patches/wish-lv2-browser-h.patch b/debian/patches/wish-lv2-browser-h.patch
new file mode 100644
index 0000000..789565a
--- /dev/null
+++ b/debian/patches/wish-lv2-browser-h.patch
@@ -0,0 +1,21 @@
+Description: This is a wishlist patch. It declares the functions to configure
+ the output widget of plugins like Lv2.
+ It is used by AgsMixer, AgsDrum, AgsFFPlayer and AgsSynth.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/ags_lv2_browser.h
++++ b/ags/X/ags_lv2_browser.h
+@@ -56,8 +56,12 @@
+ gchar* ags_lv2_browser_get_plugin_filename(AgsLv2Browser *lv2_browser);
+ gchar* ags_lv2_browser_get_plugin_effect(AgsLv2Browser *lv2_browser);
+ 
++GtkWidget* ags_lv2_browser_combo_box_output_boolean_controls_new();
++GtkWidget* ags_lv2_browser_combo_box_output_controls_new();
++
+ GtkWidget* ags_lv2_browser_combo_box_boolean_controls_new();
+ GtkWidget* ags_lv2_browser_combo_box_controls_new();
++
+ GtkWidget* ags_lv2_browser_preview_new();
+ 
+ AgsLv2Browser* ags_lv2_browser_new();
diff --git a/debian/patches/wish-mixer-input-line.patch b/debian/patches/wish-mixer-input-line.patch
new file mode 100644
index 0000000..5fcce01
--- /dev/null
+++ b/debian/patches/wish-mixer-input-line.patch
@@ -0,0 +1,44 @@
+Description: This is a wishlist patch. It changes the recall handler to the
+ generic callback, introduced in view of plugin output ports. It is responsible
+ for redrawing visible feedback.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/X/machine/ags_mixer_input_line.c
++++ b/ags/X/machine/ags_mixer_input_line.c
+@@ -62,7 +62,7 @@
+ static gpointer ags_mixer_input_line_parent_class = NULL;
+ static AgsConnectableInterface *ags_mixer_input_line_parent_connectable_interface;
+ 
+-extern GHashTable *ags_indicator_queue_draw;
++extern GHashTable *ags_line_indicator_queue_draw;
+ 
+ GType
+ ags_mixer_input_line_get_type()
+@@ -145,7 +145,7 @@
+ 		   1, 1);
+   widget = gtk_bin_get_child(GTK_BIN(line_member));
+   AGS_LINE(mixer_input_line)->indicator = widget;
+-  g_hash_table_insert(ags_indicator_queue_draw,
++  g_hash_table_insert(ags_line_indicator_queue_draw,
+ 		      widget, ags_line_indicator_queue_draw_timeout);
+   g_timeout_add(1000 / 30, (GSourceFunc) ags_line_indicator_queue_draw_timeout, (gpointer) widget);
+ 
+@@ -270,7 +270,7 @@
+     recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
+ 
+     recall_handler->signal_name = "run-post\0";
+-    recall_handler->callback = G_CALLBACK(ags_line_peak_run_post_callback);
++    recall_handler->callback = G_CALLBACK(ags_line_output_port_run_post_callback);
+     recall_handler->data = (gpointer) line;
+ 
+     ags_recall_add_handler(AGS_RECALL(play_peak_channel_run), recall_handler);
+@@ -286,7 +286,7 @@
+     recall_handler = (AgsRecallHandler *) malloc(sizeof(AgsRecallHandler));
+ 
+     recall_handler->signal_name = "run-post\0";
+-    recall_handler->callback = G_CALLBACK(ags_line_peak_run_post_callback);
++    recall_handler->callback = G_CALLBACK(ags_line_output_port_run_post_callback);
+     recall_handler->data = (gpointer) line;
+ 
+     ags_recall_add_handler(AGS_RECALL(recall_peak_channel_run), recall_handler);
diff --git a/debian/patches/wish-peak-channel.patch b/debian/patches/wish-peak-channel.patch
new file mode 100644
index 0000000..bbd4335
--- /dev/null
+++ b/debian/patches/wish-peak-channel.patch
@@ -0,0 +1,126 @@
+Description: This is a wishlist patch. It modifies AgsPort type of ags-peak recall
+ in order to use with the generic callback of output widgets.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/audio/recall/ags_peak_channel.c
++++ b/ags/audio/recall/ags_peak_channel.c
+@@ -25,6 +25,8 @@
+ #include <ags/object/ags_mutable.h>
+ #include <ags/object/ags_plugin.h>
+ 
++#include <ags/plugin/ags_base_plugin.h>
++
+ #include <ags/audio/ags_audio.h>
+ #include <ags/audio/ags_output.h>
+ #include <ags/audio/ags_input.h>
+@@ -49,6 +51,8 @@
+ void ags_peak_channel_set_ports(AgsPlugin *plugin, GList *port);
+ void ags_peak_channel_finalize(GObject *gobject);
+ 
++static AgsPortDescriptor* ags_peak_channel_get_peak_port_descriptor();
++
+ /**
+  * SECTION:ags_peak_channel
+  * @short_description: peaks channel
+@@ -171,6 +175,8 @@
+ ags_peak_channel_init(AgsPeakChannel *peak_channel)
+ {
+   GList *port;
++  
++  AGS_RECALL(peak_channel)->flags |= AGS_RECALL_HAS_OUTPUT_PORT;
+ 
+   AGS_RECALL(peak_channel)->name = "ags-peak\0";
+   AGS_RECALL(peak_channel)->version = AGS_RECALL_DEFAULT_VERSION;
+@@ -179,17 +185,25 @@
+ 
+   port = NULL;
+ 
++  /* peak */
+   peak_channel->peak = g_object_new(AGS_TYPE_PORT,
+-				     "plugin-name\0", ags_peak_channel_plugin_name,
+-				     "specifier\0", ags_peak_channel_plugin_specifier[0],
+-				     "control-port\0", ags_peak_channel_plugin_control_port[0],
+-				     "port-value-is-pointer\0", FALSE,
+-				     "port-value-type\0", G_TYPE_DOUBLE,
+-				     "port-value-size\0", sizeof(gdouble),
+-				     "port-value-length\0", 1,
+-				     NULL);
+-  peak_channel->peak->port_value.ags_port_double = FALSE;
++				    "plugin-name\0", ags_peak_channel_plugin_name,
++				    "specifier\0", ags_peak_channel_plugin_specifier[0],
++				    "control-port\0", ags_peak_channel_plugin_control_port[0],
++				    "port-value-is-pointer\0", FALSE,
++				    "port-value-type\0", G_TYPE_FLOAT,
++				    "port-value-size\0", sizeof(gfloat),
++				    "port-value-length\0", 1,
++				    NULL);
+ 
++  peak_channel->peak->flags |= AGS_PORT_IS_OUTPUT;
++  
++  peak_channel->peak->port_value.ags_port_float = FALSE;
++  
++  /* port descriptor */
++  peak_channel->peak->port_descriptor = ags_peak_channel_get_peak_port_descriptor();
++
++  /* add to port */  
+   port = g_list_prepend(port, peak_channel->peak);
+ 
+   /* set port */
+@@ -452,14 +466,14 @@
+     current_value = scale_precision * (atan(1.0 / 440.0) / sin(current_value / 22000.0));
+   }
+   
+-  g_value_init(&value, G_TYPE_DOUBLE);
++  g_value_init(&value, G_TYPE_FLOAT);
+ 
+   if(current_value < 0.0){
+     current_value *= -1.0;
+   }
+ 
+-  g_value_set_double(&value,
+-		     current_value);
++  g_value_set_float(&value,
++		    current_value);
+ 
+   ags_port_safe_write(peak_channel->peak,
+ 		      &value);
+@@ -469,6 +483,38 @@
+   free(buffer);
+ }
+ 
++static AgsPortDescriptor*
++ags_peak_channel_get_peak_port_descriptor()
++{
++  static AgsPortDescriptor *port_descriptor = NULL;
++
++  if(port_descriptor == NULL){
++    port_descriptor = ags_port_descriptor_alloc();
++
++    port_descriptor->flags |= (AGS_PORT_DESCRIPTOR_INPUT |
++			       AGS_PORT_DESCRIPTOR_CONTROL);
++
++    port_descriptor->port_index = 0;
++
++    /* range */
++    g_value_init(port_descriptor->default_value,
++		 G_TYPE_FLOAT);
++    g_value_init(port_descriptor->lower_value,
++		 G_TYPE_FLOAT);
++    g_value_init(port_descriptor->upper_value,
++		 G_TYPE_FLOAT);
++
++    g_value_set_float(port_descriptor->default_value,
++		      0.0);
++    g_value_set_float(port_descriptor->lower_value,
++		      0.0);
++    g_value_set_float(port_descriptor->upper_value,
++		      10.0);
++  }
++  
++  return(port_descriptor);
++}
++
+ /**
+  * ags_peak_channel_new:
+  * @source: the #AgsChannel as source
diff --git a/debian/patches/wish-recall-dssi.patch b/debian/patches/wish-recall-dssi.patch
new file mode 100644
index 0000000..66efe07
--- /dev/null
+++ b/debian/patches/wish-recall-dssi.patch
@@ -0,0 +1,21 @@
+Description: This is a wishlist patch. It flags the recall with appropriate
+ output port availabel in order to get detected by generic callback of output
+ widgets.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/audio/ags_recall_dssi.c
++++ b/ags/audio/ags_recall_dssi.c
+@@ -640,6 +640,12 @@
+ 			       "port-value-type\0", G_TYPE_FLOAT,
+ 			       NULL);
+ 	current->flags |= AGS_PORT_USE_LADSPA_FLOAT;
++
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  AGS_RECALL(recall_dssi)->flags |= AGS_RECALL_HAS_OUTPUT_PORT;
++
++	  current->flags |= AGS_PORT_IS_OUTPUT;
++	}
+ 	
+ 	current->port_descriptor = port_descriptor->data;
+ 	ags_recall_dssi_load_conversion(recall_dssi,
diff --git a/debian/patches/wish-recall-h.patch b/debian/patches/wish-recall-h.patch
new file mode 100644
index 0000000..5b98b8f
--- /dev/null
+++ b/debian/patches/wish-recall-h.patch
@@ -0,0 +1,16 @@
+Description: This is a wishlist patch. It introduces flag of recalls with appropriate
+ output port availabel in order to get detected by generic callback of output
+ widgets.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/audio/ags_recall.h
++++ b/ags/audio/ags_recall.h
+@@ -67,6 +67,7 @@
+   AGS_RECALL_PERSISTENT_NOTATION   = 1 << 19,
+   AGS_RECALL_SKIP_DEPENDENCIES     = 1 << 20,
+   AGS_RECALL_BULK_MODE             = 1 << 21,
++  AGS_RECALL_HAS_OUTPUT_PORT       = 1 << 22,
+ }AgsRecallFlags;
+ 
+ typedef enum{
diff --git a/debian/patches/wish-recall-lv2.patch b/debian/patches/wish-recall-lv2.patch
new file mode 100644
index 0000000..0d06c19
--- /dev/null
+++ b/debian/patches/wish-recall-lv2.patch
@@ -0,0 +1,36 @@
+Description: This is a wishlist patch. It flags the recall with appropriate
+ output port availabel in order to get detected by generic callback of output
+ widgets.
+Author: Joël Krähmann <jkraehemann at gmail.com>
+Applied-Upstream: 0.7.122.x, http://git.savannah.gnu.org/cgit/gsequencer.git
+Last-Update: 2017-02-02
+--- a/ags/audio/ags_recall_lv2.c
++++ b/ags/audio/ags_recall_lv2.c
+@@ -440,10 +440,11 @@
+     return;
+   }
+ 
+-  //  g_message("load automation %x\0", recall);
++  /* load automation */
+   ags_recall_load_automation(recall,
+ 			     g_list_copy(recall->port));
+ 
++  /* call parent */
+   ags_recall_lv2_parent_connectable_interface->connect(connectable);
+ }
+ 
+@@ -767,7 +768,13 @@
+ 			       "port-value-is-pointer\0", FALSE,
+ 			       "port-value-type\0", G_TYPE_FLOAT,
+ 			       NULL);
+-
++	
++	if((AGS_PORT_DESCRIPTOR_OUTPUT & (AGS_PORT_DESCRIPTOR(port_descriptor->data)->flags)) != 0){
++	  AGS_RECALL(recall_lv2)->flags |= AGS_RECALL_HAS_OUTPUT_PORT;
++	  
++	  current->flags |= AGS_PORT_IS_OUTPUT;
++	}
++	
+ 	current->port_descriptor = port_descriptor->data;
+ 	ags_recall_lv2_load_conversion(recall_lv2,
+ 				       (GObject *) current,

-- 
gsequencer packaging



More information about the pkg-multimedia-commits mailing list