Package: release.debian.org Severity: normal User: release.debian....@packages.debian.org Usertags: unblock
Please unblock package gsequencer There are some important bug-fixes available to gsequencer-0.7.122. The fixes provide improvements to application stability. It might look like there are many lines in the debdiff but the changes are rather small und they use proven concepts. (include/attach the debdiff against the package in testing) unblock gsequencer/0.7.122-2 -- System Information: Debian Release: 9.0 APT prefers unstable APT policy: (500, 'unstable') Architecture: amd64 (x86_64) Kernel: Linux 4.9.0+ (SMP w/24 CPU cores) Locale: LANG=C.UTF-8, LC_CTYPE=C.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Init: systemd (via /run/systemd/system)
diff -Nru gsequencer-0.7.122/debian/changelog gsequencer-0.7.122/debian/changelog --- gsequencer-0.7.122/debian/changelog 2017-01-03 17:02:45.000000000 +0100 +++ gsequencer-0.7.122/debian/changelog 2017-02-01 11:14:14.000000000 +0100 @@ -1,3 +1,13 @@ +gsequencer (0.7.122-2) unstable; urgency=medium + + [ Joël Krähemann ] + * Disabled ALSA on non-linux, and enabled OSS4 only on kFreeBSD + (Closes: #852985) + * Backported patches (from upstream) to fix crasher bugs related to thread + safety and memory corruption. + + -- Joël Krähemann <jkraehemann-gu...@users.alioth.debian.org> Wed, 01 Feb 2017 11:14:14 +0100 + gsequencer (0.7.122-1) unstable; urgency=medium * New upstream version 0.7.122 diff -Nru gsequencer-0.7.122/debian/control gsequencer-0.7.122/debian/control --- gsequencer-0.7.122/debian/control 2017-01-03 17:02:45.000000000 +0100 +++ gsequencer-0.7.122/debian/control 2017-01-31 10:31:42.000000000 +0100 @@ -20,8 +20,9 @@ dssi-dev, lv2-dev, libgmp-dev, - libasound2-dev|liboss4-salsa-dev, - oss4-dev, + libasound2-dev [linux-any], + liboss4-salsa-dev [!linux-any], + oss4-dev [kfreebsd-any], libjack-dev, uuid-dev, docbook-xsl, diff -Nru gsequencer-0.7.122/debian/patches/fix-clear-buffer-c.patch gsequencer-0.7.122/debian/patches/fix-clear-buffer-c.patch --- gsequencer-0.7.122/debian/patches/fix-clear-buffer-c.patch 1970-01-01 01:00:00.000000000 +0100 +++ gsequencer-0.7.122/debian/patches/fix-clear-buffer-c.patch 2017-02-01 10:25:06.000000000 +0100 @@ -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 <jkraehem...@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 -Nru gsequencer-0.7.122/debian/patches/fix-clear-buffer-h.patch gsequencer-0.7.122/debian/patches/fix-clear-buffer-h.patch --- gsequencer-0.7.122/debian/patches/fix-clear-buffer-h.patch 1970-01-01 01:00:00.000000000 +0100 +++ gsequencer-0.7.122/debian/patches/fix-clear-buffer-h.patch 2017-02-01 10:25:06.000000000 +0100 @@ -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 <jkraehem...@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 -Nru gsequencer-0.7.122/debian/patches/fix-copy-pattern-channel-run.patch gsequencer-0.7.122/debian/patches/fix-copy-pattern-channel-run.patch --- gsequencer-0.7.122/debian/patches/fix-copy-pattern-channel-run.patch 1970-01-01 01:00:00.000000000 +0100 +++ gsequencer-0.7.122/debian/patches/fix-copy-pattern-channel-run.patch 2017-02-01 10:25:06.000000000 +0100 @@ -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 <jkraehem...@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 -Nru gsequencer-0.7.122/debian/patches/fix-count-beats-audio-run.patch gsequencer-0.7.122/debian/patches/fix-count-beats-audio-run.patch --- gsequencer-0.7.122/debian/patches/fix-count-beats-audio-run.patch 1970-01-01 01:00:00.000000000 +0100 +++ gsequencer-0.7.122/debian/patches/fix-count-beats-audio-run.patch 2017-02-01 10:25:06.000000000 +0100 @@ -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 <jkraehem...@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 -Nru gsequencer-0.7.122/debian/patches/fix-delay-audio-run.patch gsequencer-0.7.122/debian/patches/fix-delay-audio-run.patch --- gsequencer-0.7.122/debian/patches/fix-delay-audio-run.patch 1970-01-01 01:00:00.000000000 +0100 +++ gsequencer-0.7.122/debian/patches/fix-delay-audio-run.patch 2017-02-01 10:25:06.000000000 +0100 @@ -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 <jkraehem...@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 -Nru gsequencer-0.7.122/debian/patches/fix-devout.patch gsequencer-0.7.122/debian/patches/fix-devout.patch --- gsequencer-0.7.122/debian/patches/fix-devout.patch 1970-01-01 01:00:00.000000000 +0100 +++ gsequencer-0.7.122/debian/patches/fix-devout.patch 2017-02-01 10:25:06.000000000 +0100 @@ -0,0 +1,79 @@ +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 <jkraehem...@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 -Nru gsequencer-0.7.122/debian/patches/fix-export-soundcard-callbacks.patch gsequencer-0.7.122/debian/patches/fix-export-soundcard-callbacks.patch --- gsequencer-0.7.122/debian/patches/fix-export-soundcard-callbacks.patch 1970-01-01 01:00:00.000000000 +0100 +++ gsequencer-0.7.122/debian/patches/fix-export-soundcard-callbacks.patch 2017-02-01 10:25:06.000000000 +0100 @@ -0,0 +1,45 @@ +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 <jkraehem...@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){ diff -Nru gsequencer-0.7.122/debian/patches/fix-jack-client.patch gsequencer-0.7.122/debian/patches/fix-jack-client.patch --- gsequencer-0.7.122/debian/patches/fix-jack-client.patch 1970-01-01 01:00:00.000000000 +0100 +++ gsequencer-0.7.122/debian/patches/fix-jack-client.patch 2017-02-01 10:25:06.000000000 +0100 @@ -0,0 +1,17 @@ +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 <jkraehem...@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 -Nru gsequencer-0.7.122/debian/patches/fix-jack-devout.patch gsequencer-0.7.122/debian/patches/fix-jack-devout.patch --- gsequencer-0.7.122/debian/patches/fix-jack-devout.patch 1970-01-01 01:00:00.000000000 +0100 +++ gsequencer-0.7.122/debian/patches/fix-jack-devout.patch 2017-02-01 10:25:06.000000000 +0100 @@ -0,0 +1,108 @@ +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 <jkraehem...@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 -Nru gsequencer-0.7.122/debian/patches/fix-line-callbacks.patch gsequencer-0.7.122/debian/patches/fix-line-callbacks.patch --- gsequencer-0.7.122/debian/patches/fix-line-callbacks.patch 1970-01-01 01:00:00.000000000 +0100 +++ gsequencer-0.7.122/debian/patches/fix-line-callbacks.patch 2017-02-01 10:25:06.000000000 +0100 @@ -0,0 +1,74 @@ +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 <jkraehem...@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 -Nru gsequencer-0.7.122/debian/patches/fix-machine-selector.patch gsequencer-0.7.122/debian/patches/fix-machine-selector.patch --- gsequencer-0.7.122/debian/patches/fix-machine-selector.patch 1970-01-01 01:00:00.000000000 +0100 +++ gsequencer-0.7.122/debian/patches/fix-machine-selector.patch 2017-02-01 10:25:06.000000000 +0100 @@ -0,0 +1,145 @@ +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 <jkraehem...@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 -Nru gsequencer-0.7.122/debian/patches/fix-makefile-am.patch gsequencer-0.7.122/debian/patches/fix-makefile-am.patch --- gsequencer-0.7.122/debian/patches/fix-makefile-am.patch 1970-01-01 01:00:00.000000000 +0100 +++ gsequencer-0.7.122/debian/patches/fix-makefile-am.patch 2017-02-01 10:25:06.000000000 +0100 @@ -0,0 +1,27 @@ +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 <jkraehem...@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 -Nru gsequencer-0.7.122/debian/patches/fix-pad-callbacks.patch gsequencer-0.7.122/debian/patches/fix-pad-callbacks.patch --- gsequencer-0.7.122/debian/patches/fix-pad-callbacks.patch 1970-01-01 01:00:00.000000000 +0100 +++ gsequencer-0.7.122/debian/patches/fix-pad-callbacks.patch 2017-02-01 10:25:06.000000000 +0100 @@ -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 <jkraehem...@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 -Nru gsequencer-0.7.122/debian/patches/fix-thread-posix.patch gsequencer-0.7.122/debian/patches/fix-thread-posix.patch --- gsequencer-0.7.122/debian/patches/fix-thread-posix.patch 1970-01-01 01:00:00.000000000 +0100 +++ gsequencer-0.7.122/debian/patches/fix-thread-posix.patch 2017-02-01 10:25:06.000000000 +0100 @@ -0,0 +1,35 @@ +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 <jkraehem...@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 -Nru gsequencer-0.7.122/debian/patches/fix-xorg-application-context.patch gsequencer-0.7.122/debian/patches/fix-xorg-application-context.patch --- gsequencer-0.7.122/debian/patches/fix-xorg-application-context.patch 1970-01-01 01:00:00.000000000 +0100 +++ gsequencer-0.7.122/debian/patches/fix-xorg-application-context.patch 2017-02-01 10:25:06.000000000 +0100 @@ -0,0 +1,45 @@ +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 <jkraehem...@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 -Nru gsequencer-0.7.122/debian/patches/series gsequencer-0.7.122/debian/patches/series --- gsequencer-0.7.122/debian/patches/series 1970-01-01 01:00:00.000000000 +0100 +++ gsequencer-0.7.122/debian/patches/series 2017-02-01 10:25:06.000000000 +0100 @@ -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 diff -Nru gsequencer-0.7.122/debian/rules gsequencer-0.7.122/debian/rules --- gsequencer-0.7.122/debian/rules 2017-01-03 17:02:45.000000000 +0100 +++ gsequencer-0.7.122/debian/rules 2017-01-31 10:31:42.000000000 +0100 @@ -11,7 +11,13 @@ else archconfflags += --disable-alsa endif -archconfflags += --enable-oss + + +ifeq ($(DEB_HOST_ARCH_OS),kfreebsd) + archconfflags += --enable-oss +else + archconfflags += --disable-oss +endif archconfflags += --enable-gtk-doc --enable-gtk-doc-html