[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