[SCM] gsequencer/master: providing patches to critical only bugs related to thread safety and memory corruption

jkraehemann-guest at users.alioth.debian.org jkraehemann-guest at users.alioth.debian.org
Wed Feb 1 06:56:38 UTC 2017


The following commit has been merged in the master branch:
commit f41d59a34f13a92b06cd2e1c104896bb84515779
Author: Joël Krähemann <jkraehemann-guest at users.alioth.debian.org>
Date:   Wed Feb 1 07:56:02 2017 +0100

    providing patches to critical only bugs related to thread safety and memory corruption

diff --git a/debian/patches/fix-clear-buffer-c.patch b/debian/patches/fix-clear-buffer-c.patch
new file mode 100644
index 0000000..263498c
--- /dev/null
+++ b/debian/patches/fix-clear-buffer-c.patch
@@ -0,0 +1,391 @@
+Description: AgsClearBuffer fixes data-race causing distorted audio output
+ resulting in useless audio output. Introduced due to low-latency sync
+ strategy for ALSA audio output and alsa MIDI input. Might end in application
+ crash and is required by immediate sync strategy. This patch includes the
+ c-source file of the task clearing soundcard buffers in order you can do
+ additive mixing, during ordinary run context.
+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-01-31
+--- /dev/null
++++ b/ags/audio/task/ags_clear_buffer.c
+@@ -0,0 +1,379 @@
++/* GSequencer - Advanced GTK Sequencer
++ * Copyright (C) 2005-2015 Joël Krähemann
++ *
++ * This file is part of GSequencer.
++ *
++ * GSequencer is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * GSequencer is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <ags/audio/task/ags_clear_buffer.h>
++
++#include <ags/object/ags_connectable.h>
++#include <ags/object/ags_soundcard.h>
++
++#include <ags/audio/ags_devout.h>
++#include <ags/audio/ags_midiin.h>
++
++#include <ags/audio/jack/ags_jack_devout.h>
++#include <ags/audio/jack/ags_jack_midiin.h>
++
++void ags_clear_buffer_class_init(AgsClearBufferClass *clear_buffer);
++void ags_clear_buffer_connectable_interface_init(AgsConnectableInterface *connectable);
++void ags_clear_buffer_init(AgsClearBuffer *clear_buffer);
++void ags_clear_buffer_set_property(GObject *gobject,
++					 guint prop_id,
++					 const GValue *value,
++					 GParamSpec *param_spec);
++void ags_clear_buffer_get_property(GObject *gobject,
++					 guint prop_id,
++					 GValue *value,
++					 GParamSpec *param_spec);
++void ags_clear_buffer_connect(AgsConnectable *connectable);
++void ags_clear_buffer_disconnect(AgsConnectable *connectable);
++void ags_clear_buffer_finalize(GObject *gobject);
++
++void ags_clear_buffer_launch(AgsTask *task);
++
++/**
++ * SECTION:ags_clear_buffer
++ * @short_description: switch buffer flag of device
++ * @title: AgsClearBuffer
++ * @section_id:
++ * @include: ags/audio/task/ags_clear_buffer.h
++ *
++ * The #AgsClearBuffer task switches the buffer flag of device.
++ */
++
++static gpointer ags_clear_buffer_parent_class = NULL;
++static AgsConnectableInterface *ags_clear_buffer_parent_connectable_interface;
++
++enum{
++  PROP_0,
++  PROP_DEVICE,
++};
++
++GType
++ags_clear_buffer_get_type()
++{
++  static GType ags_type_clear_buffer = 0;
++
++  if(!ags_type_clear_buffer){
++    static const GTypeInfo ags_clear_buffer_info = {
++      sizeof (AgsClearBufferClass),
++      NULL, /* base_init */
++      NULL, /* base_finalize */
++      (GClassInitFunc) ags_clear_buffer_class_init,
++      NULL, /* class_finalize */
++      NULL, /* class_data */
++      sizeof (AgsClearBuffer),
++      0,    /* n_preallocs */
++      (GInstanceInitFunc) ags_clear_buffer_init,
++    };
++
++    static const GInterfaceInfo ags_connectable_interface_info = {
++      (GInterfaceInitFunc) ags_clear_buffer_connectable_interface_init,
++      NULL, /* interface_finalize */
++      NULL, /* interface_data */
++    };
++
++    ags_type_clear_buffer = g_type_register_static(AGS_TYPE_TASK,
++							 "AgsClearBuffer\0",
++							 &ags_clear_buffer_info,
++							 0);
++
++    g_type_add_interface_static(ags_type_clear_buffer,
++				AGS_TYPE_CONNECTABLE,
++				&ags_connectable_interface_info);
++  }
++  
++  return (ags_type_clear_buffer);
++}
++
++void
++ags_clear_buffer_class_init(AgsClearBufferClass *clear_buffer)
++{
++  GObjectClass *gobject;
++  AgsTaskClass *task;
++  GParamSpec *param_spec;
++
++  ags_clear_buffer_parent_class = g_type_class_peek_parent(clear_buffer);
++
++  /* gobject */
++  gobject = (GObjectClass *) clear_buffer;
++
++  gobject->set_property = ags_clear_buffer_set_property;
++  gobject->get_property = ags_clear_buffer_get_property;
++
++  gobject->finalize = ags_clear_buffer_finalize;
++
++  /* properties */
++  /**
++   * AgsClearBuffer:device:
++   *
++   * The assigned #AgsSoundcard or #AgsSequencer
++   * 
++   * Since: 0.7.124
++   */
++  param_spec = g_param_spec_object("device\0",
++				   "device of change device\0",
++				   "The device of change device task\0",
++				   G_TYPE_OBJECT,
++				   G_PARAM_READABLE | G_PARAM_WRITABLE);
++  g_object_class_install_property(gobject,
++				  PROP_DEVICE,
++				  param_spec);
++
++  /* task */
++  task = (AgsTaskClass *) clear_buffer;
++
++  task->launch = ags_clear_buffer_launch;
++}
++
++void
++ags_clear_buffer_connectable_interface_init(AgsConnectableInterface *connectable)
++{
++  ags_clear_buffer_parent_connectable_interface = g_type_interface_peek_parent(connectable);
++
++  connectable->connect = ags_clear_buffer_connect;
++  connectable->disconnect = ags_clear_buffer_disconnect;
++}
++
++void
++ags_clear_buffer_init(AgsClearBuffer *clear_buffer)
++{
++  clear_buffer->device = NULL;
++}
++
++void
++ags_clear_buffer_set_property(GObject *gobject,
++				    guint prop_id,
++				    const GValue *value,
++				    GParamSpec *param_spec)
++{
++  AgsClearBuffer *clear_buffer;
++
++  clear_buffer = AGS_CLEAR_BUFFER(gobject);
++
++  switch(prop_id){
++  case PROP_DEVICE:
++    {
++      GObject *device;
++
++      device = (GObject *) g_value_get_object(value);
++
++      if(clear_buffer->device == (GObject *) device){
++	return;
++      }
++
++      if(clear_buffer->device != NULL){
++	g_object_unref(clear_buffer->device);
++      }
++
++      if(device != NULL){
++	g_object_ref(device);
++      }
++
++      clear_buffer->device = (GObject *) device;
++    }
++    break;
++  default:
++    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
++    break;
++  }
++}
++
++void
++ags_clear_buffer_get_property(GObject *gobject,
++				    guint prop_id,
++				    GValue *value,
++				    GParamSpec *param_spec)
++{
++  AgsClearBuffer *clear_buffer;
++
++  clear_buffer = AGS_CLEAR_BUFFER(gobject);
++
++  switch(prop_id){
++  case PROP_DEVICE:
++    {
++      g_value_set_object(value, clear_buffer->device);
++    }
++    break;
++  default:
++    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
++    break;
++  }
++}
++
++void
++ags_clear_buffer_connect(AgsConnectable *connectable)
++{
++  ags_clear_buffer_parent_connectable_interface->connect(connectable);
++
++  /* empty */
++}
++
++void
++ags_clear_buffer_disconnect(AgsConnectable *connectable)
++{
++  ags_clear_buffer_parent_connectable_interface->disconnect(connectable);
++
++  /* empty */
++}
++
++void
++ags_clear_buffer_finalize(GObject *gobject)
++{
++  G_OBJECT_CLASS(ags_clear_buffer_parent_class)->finalize(gobject);
++
++  /* empty */
++}
++
++void
++ags_clear_buffer_launch(AgsTask *task)
++{
++  AgsClearBuffer *clear_buffer;
++
++  guint nth_buffer;
++  guint word_size;
++  
++  clear_buffer = AGS_CLEAR_BUFFER(task);
++
++  if(AGS_IS_DEVOUT(clear_buffer->device)){
++    AgsDevout *devout;
++
++    devout = clear_buffer->device;
++
++    /* retrieve word size */
++    switch(devout->format){
++    case AGS_SOUNDCARD_SIGNED_8_BIT:
++      {
++	word_size = sizeof(signed char);
++      }
++      break;
++    case AGS_SOUNDCARD_SIGNED_16_BIT:
++      {
++	word_size = sizeof(signed short);
++      }
++      break;
++    case AGS_SOUNDCARD_SIGNED_24_BIT:
++      {
++	word_size = sizeof(signed long);
++      }
++      break;
++    case AGS_SOUNDCARD_SIGNED_32_BIT:
++      {
++	word_size = sizeof(signed long);
++      }
++      break;
++    case AGS_SOUNDCARD_SIGNED_64_BIT:
++      {
++	word_size = sizeof(signed long long);
++      }
++      break;
++    default:
++      g_warning("ags_clear_buffer_launch(): unsupported word size\0");
++
++      return;
++    }
++
++    
++    if((AGS_DEVOUT_BUFFER0 & (devout->flags)) != 0){
++      nth_buffer = 0;
++    }else if((AGS_DEVOUT_BUFFER1 & (devout->flags)) != 0){
++      nth_buffer = 1;
++    }else if((AGS_DEVOUT_BUFFER2 & (devout->flags)) != 0){
++      nth_buffer = 2;
++    }else if((AGS_DEVOUT_BUFFER3 & devout->flags) != 0){
++      nth_buffer = 3;
++    }
++    
++    memset(devout->buffer[nth_buffer], 0, (size_t) devout->pcm_channels * devout->buffer_size * word_size);
++  }else if(AGS_IS_JACK_DEVOUT(clear_buffer->device)){
++    AgsJackDevout *jack_devout;
++    
++    jack_devout = clear_buffer->device;
++
++    switch(jack_devout->format){
++    case AGS_SOUNDCARD_SIGNED_8_BIT:
++      {
++	word_size = sizeof(signed char);
++      }
++      break;
++    case AGS_SOUNDCARD_SIGNED_16_BIT:
++      {
++	word_size = sizeof(signed short);
++      }
++      break;
++    case AGS_SOUNDCARD_SIGNED_24_BIT:
++      {      
++	//NOTE:JK: The 24-bit linear samples use 32-bit physical space
++	word_size = sizeof(signed long);
++      }
++      break;
++    case AGS_SOUNDCARD_SIGNED_32_BIT:
++      {
++	word_size = sizeof(signed long);
++      }
++      break;
++    case AGS_SOUNDCARD_SIGNED_64_BIT:
++      {
++	word_size = sizeof(signed long long);
++      }
++      break;
++    default:    
++      g_warning("ags_clear_buffer_launch(): unsupported word size\0");
++    
++      return;
++    }
++    
++    if((AGS_JACK_DEVOUT_BUFFER0 & (jack_devout->flags)) != 0){
++      nth_buffer = 3;
++    }else if((AGS_JACK_DEVOUT_BUFFER1 & (jack_devout->flags)) != 0){
++      nth_buffer = 0;
++    }else if((AGS_JACK_DEVOUT_BUFFER2 & (jack_devout->flags)) != 0){
++      nth_buffer = 1;
++    }else if((AGS_JACK_DEVOUT_BUFFER3 & jack_devout->flags) != 0){
++      nth_buffer = 2;
++    }
++      
++    memset(jack_devout->buffer[nth_buffer], 0, (size_t) jack_devout->pcm_channels * jack_devout->buffer_size * word_size);
++  }else if(AGS_IS_MIDIIN(clear_buffer->device)){
++    //TODO:JK: implement me
++  }else if(AGS_IS_JACK_MIDIIN(clear_buffer->device)){
++    //TODO:JK: implement me
++  }
++}
++
++/**
++ * ags_clear_buffer_new:
++ * @device: the #AgsSoundcard or #AgsSequencer
++ *
++ * Creates an #AgsClearBuffer.
++ *
++ * Returns: an new #AgsClearBuffer.
++ *
++ * Since: 0.7.124
++ */
++AgsClearBuffer*
++ags_clear_buffer_new(GObject *device)
++{
++  AgsClearBuffer *clear_buffer;
++
++  clear_buffer = (AgsClearBuffer *) g_object_new(AGS_TYPE_CLEAR_BUFFER,
++							    NULL);
++
++  clear_buffer->device = device;
++
++  return(clear_buffer);
++}
diff --git a/debian/patches/fix-clear-buffer-h.patch b/debian/patches/fix-clear-buffer-h.patch
new file mode 100644
index 0000000..52c3d49
--- /dev/null
+++ b/debian/patches/fix-clear-buffer-h.patch
@@ -0,0 +1,66 @@
+Description: AgsClearBuffer fixes data-race causing distorted audio output
+ resulting in useless audio output. Introduced due to low-latency sync
+ strategy for ALSA audio output and alsa MIDI input. Might end in application
+ crash and is required by immediate sync strategy. This patch includes the
+ header file of the task clearing soundcard buffers in order you can do
+ additive mixing, during ordinary run context.
+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-01-31
+--- /dev/null
++++ b/ags/audio/task/ags_clear_buffer.h
+@@ -0,0 +1,54 @@
++/* GSequencer - Advanced GTK Sequencer
++ * Copyright (C) 2005-2015 Joël Krähemann
++ *
++ * This file is part of GSequencer.
++ *
++ * GSequencer is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * GSequencer is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef __AGS_CLEAR_BUFFER_H__
++#define __AGS_CLEAR_BUFFER_H__
++
++#include <glib.h>
++#include <glib-object.h>
++
++#include <ags/thread/ags_task.h>
++
++#define AGS_TYPE_CLEAR_BUFFER                (ags_clear_buffer_get_type())
++#define AGS_CLEAR_BUFFER(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_CLEAR_BUFFER, AgsClearBuffer))
++#define AGS_CLEAR_BUFFER_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_CLEAR_BUFFER, AgsClearBufferClass))
++#define AGS_IS_CLEAR_BUFFER(obj)             (G_TYPE_CHECK_INSTANCE_TYPE((obj), AGS_TYPE_CLEAR_BUFFER))
++#define AGS_IS_CLEAR_BUFFER_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE((class), AGS_TYPE_CLEAR_BUFFER))
++#define AGS_CLEAR_BUFFER_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS((obj), AGS_TYPE_CLEAR_BUFFER, AgsClearBufferClass))
++
++typedef struct _AgsClearBuffer AgsClearBuffer;
++typedef struct _AgsClearBufferClass AgsClearBufferClass;
++
++struct _AgsClearBuffer
++{
++  AgsTask task;
++
++  GObject *device;
++};
++
++struct _AgsClearBufferClass
++{
++  AgsTaskClass task;
++};
++
++GType ags_clear_buffer_get_type();
++
++AgsClearBuffer* ags_clear_buffer_new(GObject *device);
++
++#endif /*__AGS_CLEAR_BUFFER_H__*/
diff --git a/debian/patches/fix-copy-pattern-channel-run.patch b/debian/patches/fix-copy-pattern-channel-run.patch
new file mode 100644
index 0000000..3cd905c
--- /dev/null
+++ b/debian/patches/fix-copy-pattern-channel-run.patch
@@ -0,0 +1,108 @@
+Description: This patch includes generic mutex usage improvements. Mutices
+ protect memory and execution stacks of concurrent access. Such data-races
+ occur spurious and may end in crashing the application by SIGINT.
+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-01-31
+--- a/ags/audio/recall/ags_copy_pattern_channel_run.c
++++ b/ags/audio/recall/ags_copy_pattern_channel_run.c
+@@ -364,7 +364,7 @@
+ 						      gdouble delay, guint attack,
+ 						      AgsCopyPatternChannelRun *copy_pattern_channel_run)
+ {
+-  AgsChannel *output, *source;
++  AgsChannel *source;
+   AgsPattern *pattern;
+   AgsCopyPatternAudio *copy_pattern_audio;
+   AgsCopyPatternAudioRun *copy_pattern_audio_run;
+@@ -380,7 +380,8 @@
+ 
+   pthread_mutex_t *application_mutex;
+   pthread_mutex_t *pattern_mutex;
+-
++  pthread_mutex_t *source_mutex;
++  
+   if(delay != 0.0){
+     return;
+   }
+@@ -440,34 +441,66 @@
+ 
+   /*  */
+   if(current_bit){
++    AgsChannel *link;
+     AgsRecycling *recycling;
++    AgsRecycling *end_recycling;
+     AgsAudioSignal *audio_signal;
+ 
+     gdouble delay;
+     guint attack;
+   
++    pthread_mutex_t *link_mutex;
++    
+     //    g_message("ags_copy_pattern_channel_run_sequencer_alloc_callback - playing channel: %u; playing pattern: %u\0",
+     //	      AGS_RECALL_CHANNEL(copy_pattern_channel)->source->line,
+     //	      copy_pattern_audio_run->count_beats_audio_run->sequencer_counter);
+ 
+     /* get source */
+     source = AGS_RECALL_CHANNEL(copy_pattern_channel)->source;
++
++    pthread_mutex_lock(application_mutex);
++  
++    source_mutex = ags_mutex_manager_lookup(mutex_manager,
++					    (GObject *) source);
++    
++    pthread_mutex_unlock(application_mutex);
++    
++    /* source fields */
++    pthread_mutex_lock(source_mutex);
++
++    link = source->link;
+     
+-    /* create new audio signals */
+     recycling = source->first_recycling;
++
++    if(recycling != NULL){
++      end_recycling = source->last_recycling->next;
++    }
+     
+-    //TODO:JK: unclear
++    pthread_mutex_unlock(source_mutex);
+ 
++    /* link */
++    if(link != NULL){
++      pthread_mutex_lock(application_mutex);
++      
++      link_mutex = ags_mutex_manager_lookup(mutex_manager,
++					    (GObject *) link);
++      
++      pthread_mutex_unlock(application_mutex);
++    }
++
++    /* create audio signals */
+     if(recycling != NULL){
+       AgsRecallID *child_recall_id;
+ 
+-      while(recycling != source->last_recycling->next){
+-	if(source->link == NULL){
++      while(recycling != end_recycling){
++	if(link == NULL){
+ 	  child_recall_id = AGS_RECALL(copy_pattern_channel_run)->recall_id;
+ 	}else{
+ 	  GList *list;
+ 
+-	  list = source->link->recall_id;
++	  pthread_mutex_lock(link_mutex);
++	  
++	  list = link->recall_id;
+ 
+ 	  while(list != NULL){
+ 	    if(AGS_RECALL_ID(list->data)->recycling_context->parent == AGS_RECALL(copy_pattern_channel_run)->recall_id->recycling_context){
+@@ -481,6 +514,8 @@
+ 	  if(list == NULL){
+ 	    child_recall_id = NULL;
+ 	  }
++
++	  pthread_mutex_unlock(link_mutex);
+ 	}
+ 
+ 	audio_signal = ags_audio_signal_new(AGS_RECALL(copy_pattern_audio)->soundcard,
diff --git a/debian/patches/fix-count-beats-audio-run.patch b/debian/patches/fix-count-beats-audio-run.patch
new file mode 100644
index 0000000..c93b12b
--- /dev/null
+++ b/debian/patches/fix-count-beats-audio-run.patch
@@ -0,0 +1,126 @@
+Description: This patch includes generic mutex usage improvements. Mutices
+ protect memory and execution stacks of concurrent access. Such data-races
+ occur spurious and may end in crashing the application by SIGINT.
+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-01-31
+--- a/ags/audio/recall/ags_count_beats_audio_run.c
++++ b/ags/audio/recall/ags_count_beats_audio_run.c
+@@ -1446,38 +1446,87 @@
+   }else{      
+     if(count_beats_audio_run->sequencer_counter >= (guint) loop_end - 1.0){
+       AgsAudio *audio;
++
++      AgsMutexManager *mutex_manager;
++
+       GList *playback;
+ 
++      pthread_mutex_t *application_mutex;
++      pthread_mutex_t *audio_mutex;
++      
++      audio = AGS_RECALL_AUDIO_RUN(count_beats_audio_run)->recall_audio->audio;
++
++      mutex_manager = ags_mutex_manager_get_instance();
++      application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
++  
++      /* lookup audio mutex */
++      pthread_mutex_lock(application_mutex);
++  
++      audio_mutex = ags_mutex_manager_lookup(mutex_manager,
++					     audio);
++  
++      pthread_mutex_unlock(application_mutex);
++
++      /* reset sequencer counter */
+       count_beats_audio_run->sequencer_counter = 0;
+ 
+-      audio = AGS_RECALL_AUDIO_RUN(count_beats_audio_run)->recall_audio->audio;
++      /* get playback */
++      pthread_mutex_lock(audio_mutex);
++      
+       playback = AGS_PLAYBACK_DOMAIN(audio->playback_domain)->playback;
+ 
++      pthread_mutex_unlock(audio_mutex);
++      
+       /* emit stop signals */
+       ags_count_beats_audio_run_sequencer_stop(count_beats_audio_run,
+ 					       FALSE);
+ 
+       /* set done flag in soundcard play */
+       while(playback != NULL){
+-	if(AGS_PLAYBACK(playback->data)->recall_id[1] != NULL &&
+-	   AGS_PLAYBACK(playback->data)->recall_id[1]->recycling_context == AGS_RECALL(count_beats_audio_run)->recall_id->recycling_context){
+-	  AgsChannel *channel;
++	AgsChannel *channel;
++	AgsRecyclingContext *recycling_context;
++	
++	pthread_mutex_lock(audio_mutex);
++
++	channel = audio->output;
++	
++	if(AGS_PLAYBACK(playback->data)->recall_id[1] != NULL){
++	  recycling_context = AGS_PLAYBACK(playback->data)->recall_id[1]->recycling_context;
++	}else{
++	  recycling_context = NULL;
++	}
++
++	pthread_mutex_unlock(audio_mutex);
++
++	if(recycling_context == AGS_RECALL(count_beats_audio_run)->recall_id->recycling_context){
+ 	  AgsStreamChannelRun *stream_channel_run;
++	  
+ 	  GList *list;
+ 	  GList *recall_recycling_list, *recall_audio_signal_list;
++	  
+ 	  gboolean found;
+ 
++	  pthread_mutex_t *channel_mutex;
++
+ 	  //	    AGS_PLAYBACK(playback->data)->flags |= AGS_PLAYBACK_DONE;
+ 
++	  /* lookup channel mutex */
++	  pthread_mutex_lock(application_mutex);
++	  
++	  channel_mutex = ags_mutex_manager_lookup(mutex_manager,
++						   channel);
++	  
++	  pthread_mutex_unlock(application_mutex);
++
+ 	  /* check if to stop audio processing */
+-	  channel = audio->output;
+ 	  found = FALSE;
+ 
++	  pthread_mutex_lock(channel_mutex);
++	  
+ 	  list = channel->play;
+-
+ 	  list = ags_recall_find_type_with_recycling_context(list,
+ 							     AGS_TYPE_STREAM_CHANNEL_RUN,
+-							     (GObject *) AGS_RECALL(count_beats_audio_run)->recall_id->recycling_context);
++							     (GObject *) recycling_context);
+ 
+ 	  if(list != NULL){
+ 	    stream_channel_run = AGS_STREAM_CHANNEL_RUN(list->data);
+@@ -1500,6 +1549,8 @@
+ 	    }
+ 	  }
+ 
++	  pthread_mutex_unlock(channel_mutex);
++
+ 	  /* stop audio processing*/
+ 	  if(!found){
+ 	    ags_count_beats_audio_run_stop(count_beats_audio_run,
+@@ -1509,7 +1560,12 @@
+ 	  break;
+ 	}
+ 
+-	playback = playback->next;
++	/* iterate playback */
++	pthread_mutex_lock(audio_mutex);
++	
++      	playback = playback->next;
++
++	pthread_mutex_unlock(audio_mutex);
+       }
+ 
+       return;
diff --git a/debian/patches/fix-delay-audio-run.patch b/debian/patches/fix-delay-audio-run.patch
new file mode 100644
index 0000000..31e02dd
--- /dev/null
+++ b/debian/patches/fix-delay-audio-run.patch
@@ -0,0 +1,131 @@
+Description: This patch includes generic mutex usage improvements. Mutices
+ protect memory and execution stacks of concurrent access. Such data-races
+ occur spurious and may end in crashing the application by SIGINT.
+ There are minor code changes included fulfilled during code enhancement.
+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-01-31
+--- a/ags/audio/recall/ags_delay_audio_run.c
++++ b/ags/audio/recall/ags_delay_audio_run.c
+@@ -26,6 +26,8 @@
+ #include <ags/object/ags_soundcard.h>
+ #include <ags/object/ags_plugin.h>
+ 
++#include <ags/thread/ags_mutex_manager.h>
++
+ #include <ags/file/ags_file_stock.h>
+ #include <ags/file/ags_file_id_ref.h>
+ #include <ags/file/ags_file_lookup.h>
+@@ -441,16 +443,24 @@
+   AgsDelayAudio *delay_audio;
+   AgsDelayAudioRun *delay_audio_run;
+ 
++  AgsMutexManager *mutex_manager;
++  
+   gdouble notation_delay, sequencer_delay;
++  gdouble delay;
++  guint attack;
+ 
+   GValue value = { 0, };
+ 
++  pthread_mutex_t *application_mutex;
++  pthread_mutex_t *soundcard_mutex;
++  
+   AGS_RECALL_CLASS(ags_delay_audio_run_parent_class)->run_pre(recall);
+ 
+   //  g_message("ags_delay_audio_run_run_pre()\0");
+   
+   delay_audio_run = AGS_DELAY_AUDIO_RUN(recall);
+ 
++  /* check done */  
+   if((AGS_RECALL_PERSISTENT & (recall->flags)) == 0 &&
+      delay_audio_run->dependency_ref == 0){
+     delay_audio_run->notation_counter = 0;
+@@ -463,6 +473,17 @@
+ 
+   delay_audio = AGS_DELAY_AUDIO(AGS_RECALL_AUDIO_RUN(delay_audio_run)->recall_audio);
+ 
++  mutex_manager = ags_mutex_manager_get_instance();
++  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
++  
++  /* lookup soundcard mutex */
++  pthread_mutex_lock(application_mutex);
++  
++  soundcard_mutex = ags_mutex_manager_lookup(mutex_manager,
++					     recall->soundcard);
++  
++  pthread_mutex_unlock(application_mutex);
++
+   /* read notation-delay port */
+   g_value_init(&value, G_TYPE_DOUBLE);
+ 
+@@ -489,22 +510,22 @@
+   }else{
+     delay_audio_run->sequencer_counter += 1;
+   }
++  
++  /* delay and attack */
++  pthread_mutex_lock(soundcard_mutex);
++
++  attack = ags_soundcard_get_attack(AGS_SOUNDCARD(recall->soundcard));
++  
++  pthread_mutex_unlock(soundcard_mutex);
++  
++  delay = 0.0;
+ 
++  /* notation */
+   if(delay_audio_run->notation_counter == 0){    
+     guint run_order;
+-    gdouble delay;
+-    guint attack;
+ 
+     run_order = 0; //NOTE:JK: old hide_ref style
+ 
+-    /* delay and attack */
+-    //TODO:JK: unclear
+-    attack = ags_soundcard_get_attack(AGS_SOUNDCARD(recall->soundcard));
+-      
+-    delay = 0.0; // soundcard->delay[((soundcard->tic_counter + 1 == AGS_NOTATION_TICS_PER_BEAT) ?
+-      //		   0:
+-      //		   soundcard->tic_counter + 1)];
+-
+     //    g_message("ags_delay_audio_run_run_pre@%llu: alloc notation[%u]\0",
+     //	      delay_audio_run,
+     //	      run_order);
+@@ -521,8 +542,6 @@
+ 				       delay, attack);
+   }else{
+     guint run_order;
+-    gdouble delay;
+-    guint attack;
+ 
+     run_order = 0;
+     
+@@ -541,17 +560,9 @@
+ 				       delay, attack);
+   }
+ 
++  /* sequencer */
+   if(delay_audio_run->sequencer_counter == 0){
+     guint run_order;
+-    gdouble delay;
+-    guint attack;
+-
+-    /* delay and attack */
+-    //TODO:JK: unclear
+-    attack = ags_soundcard_get_attack(AGS_SOUNDCARD(recall->soundcard));
+-    delay = 0.0; // soundcard->delay[((soundcard->tic_counter + 1 == AGS_NOTATION_TICS_PER_BEAT) ?
+-      //		   0:
+-      //		   soundcard->tic_counter + 1)];
+ 
+     run_order = 0;
+ 
+@@ -572,8 +583,6 @@
+ 					delay, attack);
+   }else{
+     guint run_order;
+-    gdouble delay;
+-    guint attack;
+ 
+     run_order = 0;
+     
diff --git a/debian/patches/fix-devout.patch b/debian/patches/fix-devout.patch
new file mode 100644
index 0000000..405d9b9
--- /dev/null
+++ b/debian/patches/fix-devout.patch
@@ -0,0 +1,78 @@
+Description: AgsClearBuffer fixes data-race causing distorted audio output
+ resulting in useless audio output. Introduced due to low-latency sync
+ strategy for ALSA audio output and alsa MIDI input. Might end in application
+ crash and is required by immediate sync strategy.
+ These changes make use of the task by ags_devout_alsa_play() and
+ ags_devout_oss_play().
+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-01-31 --- a/ags/audio/ags_devout.c
++++ b/ags/audio/ags_devout.c
+@@ -33,6 +33,7 @@
+ #include <ags/thread/ags_poll_fd.h>
+ 
+ #include <ags/audio/task/ags_tic_device.h>
++#include <ags/audio/task/ags_clear_buffer.h>
+ #include <ags/audio/task/ags_switch_buffer_flag.h>
+ #include <ags/audio/task/ags_notify_soundcard.h>
+ 
+@@ -2210,6 +2211,7 @@
+   AgsDevout *devout;
+ 
+   AgsTicDevice *tic_device;
++  AgsClearBuffer *clear_buffer;
+   AgsSwitchBufferFlag *switch_buffer_flag;
+   
+   AgsThread *task_thread;
+@@ -2402,9 +2404,6 @@
+     nth_ring_buffer = 1;
+   }
+ 
+-  /* clear next buffer */
+-  memset(devout->buffer[next_buffer], 0, (size_t) devout->pcm_channels * devout->buffer_size * word_size);
+-
+ #ifdef AGS_WITH_OSS    
+   /* fill ring buffer */
+   ags_devout_oss_play_fill_ring_buffer(devout->buffer[nth_buffer],
+@@ -2434,6 +2433,11 @@
+   tic_device = ags_tic_device_new((GObject *) devout);
+   task = g_list_append(task,
+ 		       tic_device);
++
++  /* reset - clear buffer */
++  clear_buffer = ags_clear_buffer_new((GObject *) devout);
++  task = g_list_append(task,
++		       clear_buffer);
+   
+   /* reset - switch buffer flags */
+   switch_buffer_flag = ags_switch_buffer_flag_new((GObject *) devout);
+@@ -2951,6 +2955,7 @@
+   AgsDevout *devout;
+ 
+   AgsTicDevice *tic_device;
++  AgsClearBuffer *clear_buffer;
+   AgsSwitchBufferFlag *switch_buffer_flag;
+   
+   AgsThread *task_thread;
+@@ -3166,9 +3171,6 @@
+     nth_ring_buffer = 1;
+   }
+ 
+-  /* clear next buffer */
+-  memset(devout->buffer[next_buffer], 0, (size_t) devout->pcm_channels * devout->buffer_size * word_size);
+-
+ #ifdef AGS_WITH_ALSA
+ 
+   /* fill ring buffer */
+@@ -3227,6 +3229,11 @@
+   tic_device = ags_tic_device_new((GObject *) devout);
+   task = g_list_append(task,
+ 		       tic_device);
++
++  /* reset - clear buffer */
++  clear_buffer = ags_clear_buffer_new((GObject *) devout);
++  task = g_list_append(task,
++		       clear_buffer);
+   
+   /* reset - switch buffer flags */
+   switch_buffer_flag = ags_switch_buffer_flag_new((GObject *) devout);
diff --git a/debian/patches/fix-export-soundcard-callbacks.patch b/debian/patches/fix-export-soundcard-callbacks.patch
new file mode 100644
index 0000000..7b91556
--- /dev/null
+++ b/debian/patches/fix-export-soundcard-callbacks.patch
@@ -0,0 +1,82 @@
+Description: This patch fixes a memory corruption causing program instability.
+ It did a cast to a wrong GObject sub-class and ignored possible NULL pointer.
+ Prior appeared during application start warning and critical log messages.
+ Indicating something was wrong, it is fixed now.
+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-01-31 --- a/ags/X/ags_export_soundcard_callbacks.c
++++ b/ags/X/ags_export_soundcard_callbacks.c
+@@ -61,12 +61,16 @@
+   soundcard = NULL;
+ 
+   if(application_context != NULL){
+-    soundcard = ags_sound_provider_get_soundcard(AGS_SOUNDCARD(application_context));
++    soundcard = ags_sound_provider_get_soundcard(AGS_SOUND_PROVIDER(application_context));
+   }
+ 
+   backend = gtk_combo_box_text_get_active_text(export_soundcard->backend);
+   device = gtk_combo_box_text_get_active_text(export_soundcard->card);
+ 
++  if(device == NULL){
++    return;
++  }
++  
+   found_card = FALSE;
+   
+   while(soundcard != NULL){
+@@ -154,12 +158,16 @@
+   soundcard = NULL;
+     
+   if(application_context != NULL){
+-    soundcard = ags_sound_provider_get_soundcard(AGS_SOUNDCARD(application_context));
++    soundcard = ags_sound_provider_get_soundcard(AGS_SOUND_PROVIDER(application_context));
+   }
+ 
+   backend = gtk_combo_box_text_get_active_text(export_soundcard->backend);
+   device = gtk_combo_box_text_get_active_text(export_soundcard->card);
+ 
++  if(device == NULL){
++    return;
++  }
++  
+   found_card = FALSE;
+ 
+   while(soundcard != NULL){
+--- a/ags/X/ags_export_soundcard_callbacks.c
++++ b/ags/X/ags_export_soundcard_callbacks.c
+@@ -61,12 +61,16 @@
+   soundcard = NULL;
+ 
+   if(application_context != NULL){
+-    soundcard = ags_sound_provider_get_soundcard(AGS_SOUNDCARD(application_context));
++    soundcard = ags_sound_provider_get_soundcard(AGS_SOUND_PROVIDER(application_context));
+   }
+ 
+   backend = gtk_combo_box_text_get_active_text(export_soundcard->backend);
+   device = gtk_combo_box_text_get_active_text(export_soundcard->card);
+ 
++  if(device == NULL){
++    return;
++  }
++  
+   found_card = FALSE;
+   
+   while(soundcard != NULL){
+@@ -154,12 +158,16 @@
+   soundcard = NULL;
+     
+   if(application_context != NULL){
+-    soundcard = ags_sound_provider_get_soundcard(AGS_SOUNDCARD(application_context));
++    soundcard = ags_sound_provider_get_soundcard(AGS_SOUND_PROVIDER(application_context));
+   }
+ 
+   backend = gtk_combo_box_text_get_active_text(export_soundcard->backend);
+   device = gtk_combo_box_text_get_active_text(export_soundcard->card);
+ 
++  if(device == NULL){
++    return;
++  }
++  
+   found_card = FALSE;
+ 
+   while(soundcard != NULL){
diff --git a/debian/patches/fix-jack-client.patch b/debian/patches/fix-jack-client.patch
new file mode 100644
index 0000000..19c922d
--- /dev/null
+++ b/debian/patches/fix-jack-client.patch
@@ -0,0 +1,16 @@
+Description: This fix eliminates clearing buffer by memset(). The AgsClearBuffer
+ task is used instead in ags_jack_devout.c. Related to data-race and concurrent
+ access causing possible SIGINT.
+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-01-31 --- a/ags/audio/jack/ags_jack_client.c
++++ b/ags/audio/jack/ags_jack_client.c
+@@ -886,8 +886,6 @@
+       }
+     
+       if(!no_event){
+-	memset(jack_devout->buffer[nth_buffer], 0, (size_t) jack_devout->pcm_channels * jack_devout->buffer_size * word_size);
+-
+ 	/* signal finish */
+ 	pthread_mutex_lock(device_mutex);
+ 
diff --git a/debian/patches/fix-jack-devout.patch b/debian/patches/fix-jack-devout.patch
new file mode 100644
index 0000000..fd94828
--- /dev/null
+++ b/debian/patches/fix-jack-devout.patch
@@ -0,0 +1,107 @@
+Description: AgsClearBuffer fixes data-race causing distorted audio output
+ resulting in useless audio output. Introduced due to low-latency sync
+ strategy for ALSA audio output and alsa MIDI input. Might end in application
+ crash and is required by immediate sync strategy.
+ These changes make use of the task by ags_jack_devout_port_play().
+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-01-31--- a/ags/audio/jack/ags_jack_devout.c
++++ b/ags/audio/jack/ags_jack_devout.c
+@@ -40,6 +40,7 @@
+ 
+ #include <ags/audio/task/ags_notify_soundcard.h>
+ #include <ags/audio/task/ags_tic_device.h>
++#include <ags/audio/task/ags_clear_buffer.h>
+ #include <ags/audio/task/ags_switch_buffer_flag.h>
+ 
+ #include <ags/audio/thread/ags_audio_loop.h>
+@@ -1609,7 +1610,7 @@
+ {
+   AgsJackClient *jack_client;
+   AgsJackDevout *jack_devout;
+-
++  
+   AgsMutexManager *mutex_manager;
+   AgsTaskThread *task_thread;
+ 
+@@ -1728,6 +1729,7 @@
+ 
+   if(task_thread != NULL){
+     AgsTicDevice *tic_device;
++    AgsClearBuffer *clear_buffer;
+     AgsSwitchBufferFlag *switch_buffer_flag;
+       
+     GList *task;
+@@ -1738,7 +1740,12 @@
+     tic_device = ags_tic_device_new((GObject *) jack_devout);
+     task = g_list_append(task,
+ 			 tic_device);
+-  
++
++    /* reset - clear buffer */
++    clear_buffer = ags_clear_buffer_new((GObject *) jack_devout);
++    task = g_list_append(task,
++			 clear_buffer); 
++    
+     /* reset - switch buffer flags */
+     switch_buffer_flag = ags_switch_buffer_flag_new((GObject *) jack_devout);
+     task = g_list_append(task,
+@@ -1748,9 +1755,57 @@
+     ags_task_thread_append_tasks((AgsTaskThread *) task_thread,
+ 				 task);
+   }else{
++    guint nth_buffer;
++    guint word_size;
++    
+     /* tic */
+     ags_soundcard_tic(AGS_SOUNDCARD(jack_devout));
+-	  
++
++    switch(jack_devout->format){
++    case AGS_SOUNDCARD_SIGNED_8_BIT:
++      {
++	word_size = sizeof(signed char);
++      }
++      break;
++    case AGS_SOUNDCARD_SIGNED_16_BIT:
++      {
++	word_size = sizeof(signed short);
++      }
++      break;
++    case AGS_SOUNDCARD_SIGNED_24_BIT:
++      {
++	//NOTE:JK: The 24-bit linear samples use 32-bit physical space
++	word_size = sizeof(signed long);
++      }
++      break;
++    case AGS_SOUNDCARD_SIGNED_32_BIT:
++      {
++	word_size = sizeof(signed long);
++      }
++      break;
++    case AGS_SOUNDCARD_SIGNED_64_BIT:
++      {
++	word_size = sizeof(signed long long);
++      }
++      break;
++    default:
++      g_warning("ags_jack_devout_port_play(): unsupported word size\0");
++      return;
++    }
++        
++    /* reset - clear buffer */
++    if((AGS_JACK_DEVOUT_BUFFER0 & (jack_devout->flags)) != 0){
++      nth_buffer = 3;
++    }else if((AGS_JACK_DEVOUT_BUFFER1 & (jack_devout->flags)) != 0){
++      nth_buffer = 0;
++    }else if((AGS_JACK_DEVOUT_BUFFER2 & (jack_devout->flags)) != 0){
++      nth_buffer = 1;
++    }else if((AGS_JACK_DEVOUT_BUFFER3 & jack_devout->flags) != 0){
++      nth_buffer = 2;
++    }
++    
++    memset(jack_devout->buffer[nth_buffer], 0, (size_t) jack_devout->pcm_channels * jack_devout->buffer_size * word_size);
++    
+     /* reset - switch buffer flags */
+     ags_jack_devout_switch_buffer_flag(jack_devout);
+   }
diff --git a/debian/patches/fix-line-callbacks.patch b/debian/patches/fix-line-callbacks.patch
new file mode 100644
index 0000000..efbfc55
--- /dev/null
+++ b/debian/patches/fix-line-callbacks.patch
@@ -0,0 +1,73 @@
+Description: Due to spurious crashes while clicking pad's play button there
+ was a need to improve the involved mutices. Expected result better stability.
+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-01-31--- a/ags/X/ags_line_callbacks.c
++++ b/ags/X/ags_line_callbacks.c
+@@ -423,27 +423,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/fix-machine-selector.patch b/debian/patches/fix-machine-selector.patch
new file mode 100644
index 0000000..3ccba1f
--- /dev/null
+++ b/debian/patches/fix-machine-selector.patch
@@ -0,0 +1,144 @@
+Description: Since AgsAutomationEditor and AgsEditor have the AgsMachineSelector
+ composite widget as a common component, the migration wasn't done properly.
+ The code to handle automation editor was just missing and caused crashes due
+ to memory corruption.
+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-01-31--- a/ags/X/editor/ags_machine_selector.c
++++ b/ags/X/editor/ags_machine_selector.c
+@@ -25,6 +25,7 @@
+ #include <ags/audio/ags_notation.h>
+ 
+ #include <ags/X/ags_editor.h>
++#include <ags/X/ags_automation_editor.h>
+ 
+ #include <ags/X/editor/ags_machine_radio_button.h>
+ 
+@@ -225,10 +226,7 @@
+   
+   GList *list, *list_start;
+ 
+-  editor = (AgsEditor *) gtk_widget_get_ancestor((GtkWidget *) machine_selector,
+-						 AGS_TYPE_EDITOR);
+-
+-  /* emit changed */
++  /* get machine radio button */
+   machine_radio_button = NULL;
+ 
+   list_start = 
+@@ -243,28 +241,106 @@
+   }
+   
+   g_list_free(list_start);
++
++  if(machine_radio_button == NULL){
++    return;
++  }
+   
+-  /* destroy edit widgets */
+-  if(machine_radio_button != NULL){
++  /*  */
++  editor = (AgsEditor *) gtk_widget_get_ancestor((GtkWidget *) machine_selector,
++						 AGS_TYPE_EDITOR);
++
++  if(editor != NULL){  
++    /* destroy edit widgets */
+     if(machine_radio_button->machine != NULL){
++      AgsEditorChild *editor_child;
++
++      editor_child = NULL;
++      
+       list = editor->editor_child;
+ 
+       while(list != NULL){
+ 	if(AGS_EDITOR_CHILD(list->data)->machine == machine_radio_button->machine){
+-	  gtk_widget_destroy((GtkWidget *) AGS_EDITOR_CHILD(list->data)->notebook);
+-	  gtk_widget_destroy((GtkWidget *) AGS_EDITOR_CHILD(list->data)->meter);
+-	  gtk_widget_destroy((GtkWidget *) AGS_EDITOR_CHILD(list->data)->edit_widget);
+-	
++	  editor_child = AGS_EDITOR_CHILD(list->data);
++	  
++	  gtk_widget_destroy((GtkWidget *) editor_child->notebook);
++	  gtk_widget_destroy((GtkWidget *) editor_child->meter);
++	  gtk_widget_destroy((GtkWidget *) editor_child->edit_widget);
++
++	  editor->current_notebook = NULL;
++	  editor->current_meter = NULL;
++	  editor->current_edit_widget = NULL;
++	  
+ 	  break;
+ 	}
+     
+ 	list = list->next;
+       }
++
++      if(editor_child != NULL){
++	editor->editor_child = g_list_remove(editor->editor_child,
++					     editor_child);
++	free(editor_child);
++      }
++    }
++  }else{
++    AgsAutomationEditor *automation_editor;
++    
++    automation_editor = (AgsAutomationEditor *) gtk_widget_get_ancestor((GtkWidget *) machine_selector,
++									AGS_TYPE_AUTOMATION_EDITOR);
++
++    if(automation_editor != NULL){
++      /* destroy edit widgets */
++      if(machine_radio_button->machine != NULL){
++	AgsAutomationEditorChild *automation_editor_child;
++
++	automation_editor_child = NULL;
++	
++	list = automation_editor->automation_editor_child;
++
++	while(list != NULL){
++	  if(AGS_AUTOMATION_EDITOR_CHILD(list->data)->machine == machine_radio_button->machine){
++	    automation_editor_child = AGS_AUTOMATION_EDITOR_CHILD(list->data);
++	    
++	    gtk_widget_destroy((GtkWidget *) automation_editor_child->audio_scale);
++	    gtk_widget_destroy((GtkWidget *) automation_editor_child->audio_automation_edit);
++	    
++	    gtk_widget_destroy((GtkWidget *) automation_editor_child->output_scale);
++	    gtk_widget_destroy((GtkWidget *) automation_editor_child->output_notebook);
++	    gtk_widget_destroy((GtkWidget *) automation_editor_child->output_automation_edit);
++
++	    gtk_widget_destroy((GtkWidget *) automation_editor_child->input_scale);
++	    gtk_widget_destroy((GtkWidget *) automation_editor_child->input_notebook);
++	    gtk_widget_destroy((GtkWidget *) automation_editor_child->input_automation_edit);
++
++	    automation_editor->current_audio_scale = NULL;
++	    automation_editor->current_audio_automation_edit = NULL;
++
++	    automation_editor->current_output_notebook = NULL;
++	    automation_editor->current_output_scale = NULL;
++	    automation_editor->current_output_automation_edit = NULL;
++
++	    automation_editor->current_input_notebook = NULL;
++	    automation_editor->current_input_scale = NULL;
++	    automation_editor->current_input_automation_edit = NULL;
++
++	    break;
++	  }
++    
++	  list = list->next;
++	}
++
++	if(automation_editor_child != NULL){
++	  automation_editor->automation_editor_child = g_list_remove(automation_editor->automation_editor_child,
++								     automation_editor_child);
++	  free(automation_editor_child);
++	}
++      }
+     }
+-  
+-    /**/
+-    gtk_widget_destroy(GTK_WIDGET(machine_radio_button));
+   }
++  
++  /**/
++  gtk_widget_destroy(GTK_WIDGET(machine_radio_button));
+ }
+ 
+ void
diff --git a/debian/patches/fix-makefile-am.patch b/debian/patches/fix-makefile-am.patch
new file mode 100644
index 0000000..117d47f
--- /dev/null
+++ b/debian/patches/fix-makefile-am.patch
@@ -0,0 +1,26 @@
+Description: AgsClearBuffer fixes data-race causing distorted audio output
+ resulting in useless audio output. Introduced due to low-latency sync
+ strategy for ALSA audio output and alsa MIDI input. Might end in application
+ crash and is required by immediate sync strategy.
+ This patch includes the Makefile.am fixes to use the new object and its
+ functions.
+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-01-31 --- a/Makefile.am
++++ b/Makefile.am
+@@ -963,6 +963,7 @@
+ 	ags/audio/task/ags_cancel_channel.h \
+ 	ags/audio/task/ags_cancel_recall.h \
+ 	ags/audio/task/ags_change_soundcard.h \
++	ags/audio/task/ags_clear_buffer.h \
+ 	ags/audio/task/ags_export_output.h \
+ 	ags/audio/task/ags_free_selection.h \
+ 	ags/audio/task/ags_init_audio.h \
+@@ -1024,6 +1025,7 @@
+ 	ags/audio/task/ags_cancel_channel.c \
+ 	ags/audio/task/ags_cancel_recall.c \
+ 	ags/audio/task/ags_change_soundcard.c \
++	ags/audio/task/ags_clear_buffer.c \
+ 	ags/audio/task/ags_export_output.c \
+ 	ags/audio/task/ags_free_selection.c \
+ 	ags/audio/task/ags_init_audio.c \
diff --git a/debian/patches/fix-pad-callbacks.patch b/debian/patches/fix-pad-callbacks.patch
new file mode 100644
index 0000000..02c0ad7
--- /dev/null
+++ b/debian/patches/fix-pad-callbacks.patch
@@ -0,0 +1,128 @@
+Description: Due to spurious crashes while clicking pad's play button there
+ was a need to improve the involved mutices. Expected result better stability.
+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-01-31
+--- a/ags/X/ags_pad_callbacks.c
++++ b/ags/X/ags_pad_callbacks.c
+@@ -33,6 +33,7 @@
+ #include <ags/audio/ags_playback.h>
+ #include <ags/audio/ags_pattern.h>
+ #include <ags/audio/ags_recall.h>
++#include <ags/audio/ags_recall_id.h>
+ 
+ #include <ags/audio/thread/ags_audio_loop.h>
+ #include <ags/audio/thread/ags_soundcard_thread.h>
+@@ -325,6 +326,7 @@
+ ags_pad_init_channel_launch_callback(AgsTask *task, AgsPad *input_pad)
+ { 
+   AgsSoundcard *soundcard;
++  AgsAudio *audio;
+   AgsChannel *channel, *next_pad;
+   AgsRecycling *recycling, *end_recycling;
+ 
+@@ -338,11 +340,28 @@
+   pthread_mutex_t *application_mutex;
+   pthread_mutex_t *audio_mutex;
+   pthread_mutex_t *channel_mutex;
++  pthread_mutex_t *recycling_mutex;
+  
+   mutex_manager = ags_mutex_manager_get_instance();
+   application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
+ 
+-  /* get audio loop and audio mutex */
++  /* get channel and its mutex */
++  channel = input_pad->channel;
++
++  pthread_mutex_lock(application_mutex);
++
++  channel_mutex = ags_mutex_manager_lookup(mutex_manager,
++					   (GObject *) channel);
++
++  pthread_mutex_unlock(application_mutex);
++
++  /* get audio and its audio mutex */
++  pthread_mutex_lock(channel_mutex);
++
++  audio = AGS_AUDIO(channel->audio);
++  
++  pthread_mutex_unlock(channel_mutex);
++
+   pthread_mutex_lock(application_mutex);
+   
+   audio_mutex = ags_mutex_manager_lookup(mutex_manager,
+@@ -353,7 +372,7 @@
+   /* get soundcard */
+   pthread_mutex_lock(audio_mutex);
+   
+-  soundcard = AGS_SOUNDCARD(AGS_AUDIO(input_pad->channel->audio)->soundcard);
++  soundcard = AGS_SOUNDCARD(audio->soundcard);
+   
+   pthread_mutex_unlock(audio_mutex);
+ 
+@@ -361,16 +380,6 @@
+   list_start = 
+     list = gtk_container_get_children((GtkContainer *) input_pad->expander_set);
+ 
+-  /* get channel and its mutex */
+-  channel = input_pad->channel;
+-
+-  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);
+   
+@@ -407,6 +416,7 @@
+     
+     if(recall != NULL){
+       AgsAudioSignal *audio_signal;
++      AgsRecallID *current_recall_id;
+       
+       g_signal_connect_after(channel, "done\0",
+ 			     G_CALLBACK(ags_line_channel_done_callback), AGS_LINE(list->data));
+@@ -416,13 +426,25 @@
+       
+       recycling = channel->first_recycling;
+       end_recycling = channel->last_recycling->next;
++
++      current_recall_id = AGS_RECALL(recall->data)->recall_id;
+       
+       pthread_mutex_unlock(channel_mutex);
+ 
+       while(recycling != end_recycling){
++	/* get recycling mutex */
++	pthread_mutex_lock(application_mutex);
++  
++	recycling_mutex = ags_mutex_manager_lookup(mutex_manager,
++						   (GObject *) recycling);
++	
++	pthread_mutex_unlock(application_mutex);
++
++	/* instantiate audio signal */
+ 	audio_signal = ags_audio_signal_new((GObject *) soundcard,
+ 					    (GObject *) recycling,
+-					    (GObject *) AGS_RECALL(recall->data)->recall_id);
++					    (GObject *) current_recall_id);
++	
+ 	/* add audio signal */
+ 	ags_recycling_create_audio_signal_with_defaults(recycling,
+ 							audio_signal,
+@@ -436,7 +458,13 @@
+ 	ags_recycling_add_audio_signal(recycling,
+ 				       audio_signal);
+ 
++
++	/* iterate recycling */
++	pthread_mutex_lock(recycling_mutex);
++
+ 	recycling = recycling->next;
++
++	pthread_mutex_unlock(recycling_mutex);
+       }    
+     }
+ 
diff --git a/debian/patches/fix-thread-posix.patch b/debian/patches/fix-thread-posix.patch
new file mode 100644
index 0000000..7f9fead
--- /dev/null
+++ b/debian/patches/fix-thread-posix.patch
@@ -0,0 +1,34 @@
+Description: This patch is considered critical since it fixes the beginning
+ of the data-race. It has a strong relation with soundcard output. Since
+ the start of threads has some uncertainity about when it is ready. It
+ has a need for 2 tics to be ready and not only 1.
+ Note this is a work-around, better would be add 1 tic to tic_delay field as
+ it's in sync. But it's not evident when it happens.
+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-01-31 --- a/ags/thread/ags_thread-posix.c
++++ b/ags/thread/ags_thread-posix.c
+@@ -2288,6 +2288,7 @@
+ 	
+ 	chaos_tree = ags_thread_chaos_tree(thread);
+ 
++	//FIXME:JK: it works but I think its wrong
+ 	/* set tic delay */
+ 	if((AGS_THREAD_INTERMEDIATE_PRE_SYNC & (g_atomic_int_get(&(thread->flags)))) != 0){
+ 	  /* intermediate pre sync */
+@@ -2298,10 +2299,12 @@
+ 	  }
+ 	}else if((AGS_THREAD_INTERMEDIATE_POST_SYNC & (g_atomic_int_get(&(thread->flags)))) != 0){
+ 	  /* intermediate post sync */
+-	  if(chaos_tree->tic_delay < thread->delay){
+-	    thread->tic_delay = chaos_tree->tic_delay + 1;
+-	  }else{
++	  if(chaos_tree->tic_delay + 1 < thread->delay){
++	    thread->tic_delay = chaos_tree->tic_delay + 2;
++	  }else if(chaos_tree->tic_delay + 1 == thread->delay){
+ 	    thread->tic_delay = 0;
++	  }else{
++	    thread->tic_delay = 1;
+ 	  }
+ 	}else{
+ 	  /* ordinary sync */
diff --git a/debian/patches/fix-xorg-application-context.patch b/debian/patches/fix-xorg-application-context.patch
new file mode 100644
index 0000000..318cfa4
--- /dev/null
+++ b/debian/patches/fix-xorg-application-context.patch
@@ -0,0 +1,44 @@
+Description: This patch is believed to be important. Since the was some critical
+ messages about not finding the type, we call it's appropriate get_type() function.
+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-01 --- a/ags/X/ags_xorg_application_context.c
++++ b/ags/X/ags_xorg_application_context.c
+@@ -63,6 +63,9 @@
+ #include <ags/audio/jack/ags_jack_port.h>
+ #include <ags/audio/jack/ags_jack_devout.h>
+ 
++#include <ags/audio/task/ags_cancel_audio.h>
++#include <ags/audio/task/ags_cancel_channel.h>
++
+ #include <ags/audio/recall/ags_play_audio.h>
+ #include <ags/audio/recall/ags_play_channel.h>
+ #include <ags/audio/recall/ags_play_channel_run.h>
+@@ -634,10 +637,10 @@
+   */
+     
+   /* AgsWindow */
+-  window = ags_window_new((GObject *) xorg_application_context);
+-  g_object_set(window,
+-	       "soundcard\0", soundcard,
+-	       NULL);
++  window = g_object_new(AGS_TYPE_WINDOW,
++			"soundcard\0", soundcard,
++			"application-context\0", xorg_application_context,
++			NULL);
+   AGS_XORG_APPLICATION_CONTEXT(xorg_application_context)->window = window;
+   g_object_ref(G_OBJECT(window));
+ 
+@@ -982,6 +985,12 @@
+   /*  */
+   ags_audio_file_get_type();
+   ags_audio_file_link_get_type();
++
++  /* register tasks */
++  ags_cancel_audio_get_type();
++  ags_cancel_channel_get_type();
++  
++  //TODO:JK: extend me
+   
+   /* register recalls */
+   ags_recall_channel_run_dummy_get_type();
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..84a915b
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,15 @@
+fix-xorg-application-context.patch
+fix-thread-posix.patch
+fix-makefile-am.patch
+fix-machine-selector.patch
+fix-pad-callbacks.patch
+fix-line-callbacks.patch
+fix-export-soundcard-callbacks.patch
+fix-jack-devout.patch
+fix-jack-client.patch
+fix-delay-audio-run.patch
+fix-count-beats-audio-run.patch
+fix-copy-pattern-channel-run.patch
+fix-clear-buffer-h.patch
+fix-clear-buffer-c.patch
+fix-devout.patch

-- 
gsequencer packaging



More information about the pkg-multimedia-commits mailing list