[SCM] gsequencer/master: New upstream version 1.4.5

jkraehemann-guest at users.alioth.debian.org jkraehemann-guest at users.alioth.debian.org
Tue Jan 16 14:12:03 UTC 2018


The following commit has been merged in the master branch:
commit c36f1f78b4e6ac12e17d013af53050091250e247
Author: Joël Krähemann <jkraehemann at gmail.com>
Date:   Tue Jan 16 14:18:47 2018 +0100

    New upstream version 1.4.5

diff --git a/ChangeLog b/ChangeLog
index aa4ee07..456b21c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,58 @@
+ags (1.4.5)
+
+	[ Joël Krähemann (Maintainer of Advanced Gtk+ Sequencer) ]
+	* conservative default configuration
+	* fixed SIGSEGV as configuring super-threaded scope audio
+	* fixed SIGSEGV during ags_channel_recursive_cancel()
+
+ags (1.4.4)
+
+	[ Joël Krähemann (Maintainer of Advanced Gtk+ Sequencer) ]
+	* fixed mutex access in ags_apply_bpm.c
+	* fixed crash during ags_recycling_context_reset() and ags_channel_recursive_play_down()
+	* updated gtk-doc related files
+
+ags (1.4.3)
+
+	[ Joël Krähemann (Maintainer of Advanced Gtk+ Sequencer) ]
+	* fixed looped audio signal
+
+ags (1.4.2)
+
+	[ Joël Krähemann (Maintainer of Advanced Gtk+ Sequencer) ]
+	* more-fixes to return from unneeded processing
+
+ags (1.4.1)
+
+	[ Joël Krähemann (Maintainer of Advanced Gtk+ Sequencer) ]
+	* fixed return from unneeded processing
+
+ags (1.4.0)
+
+	[ Joël Krähemann (Maintainer of Advanced Gtk+ Sequencer) ]
+	* implemented rt-safe mode
+	* implemented ags-rt-stream recall
+	* implemented AgsLevel, AgsLevelBox, AgsVLevelBox, AgsHScaleBox and AgsScrolledScaleBox in libags-gui
+	* fixed potential SIGSEGV in ags_devout_pcm_info()
+
+ags (1.3.6)
+
+	[ Joël Krähemann (Maintainer of Advanced Gtk+ Sequencer) ]
+	* improved use of paned widgets to use GtkViewport
+
+ags (1.3.5)
+
+	[ Joël Krähemann (Maintainer of Advanced Gtk+ Sequencer) ]
+	* fixed ags_notation.c and ags_automation.c to always match timestamp
+	* increased timeouts of functional tests because build environment might have not much power
+
+ags (1.3.4)
+
+	[ Joël Krähemann (Maintainer of Advanced Gtk+ Sequencer) ]
+	* fixed paste only as within defined offset of AgsNotation and AgsAutomation
+	* fixed ags_notation_edit_draw_selection() to use vscrollbar to determine y offset
+	* improved selection to select only within area
+
 ags (1.3.3)
 
 	[ Joël Krähemann (Maintainer of Advanced Gtk+ Sequencer) ]
diff --git a/Makefile.am b/Makefile.am
index 4ce3569..c97720f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -7,6 +7,7 @@ SUBDIRS = po
 
 ACLOCAL_AMFLAGS = -I m4
 AM_CPPFLAGS = -std=gnu99 -include /usr/include/errno.h -I$(top_srcdir) -DSRCDIR=\"$(srcdir)\" -DDESTDIR=\"$(DESTDIR)$(datadir)\" -DPACKAGE_VERSION=\"$(PACKAGE_VERSION)\" -DAGS_LIBRARY_SUFFIX=\".so\" -D_FORTIFY_SOURCE=2 -Wformat -Werror=format-security
+# -msse2 -O3 -ftree-vectorize -ftree-slp-vectorize -ffast-math -ftree-vectorizer-verbose=2
 
 # what flags you want to pass to the C compiler & linker
 CFLAGS = @CFLAGS@
@@ -323,6 +324,7 @@ deprecated_libags_h_sources =
 
 libags_h_sources = \
 	$(deprecated_libags_h_sources) \
+	ags/lib/ags_buffer_util.h \
 	ags/lib/ags_complex.h \
 	ags/lib/ags_conversion.h \
 	ags/lib/ags_endian.h \
@@ -339,6 +341,7 @@ deprecated_libags_c_sources =
 
 libags_c_sources = \
 	$(deprecated_libags_c_sources) \
+	ags/lib/ags_buffer_util.c \
 	ags/lib/ags_complex.c \
 	ags/lib/ags_conversion.c \
 	ags/lib/ags_endian.c \
@@ -637,6 +640,7 @@ libags_audio_h_sources = \
 	ags/audio/ags_audio_connection.h \
 	ags/audio/ags_audio_signal.h \
 	ags/audio/ags_automation.h \
+	ags/audio/ags_buffer.h \
 	ags/audio/ags_channel.h \
 	ags/audio/ags_channel_iter.h \
 	ags/audio/ags_devout.h \
@@ -679,7 +683,8 @@ libags_audio_h_sources = \
 	ags/audio/ags_recycling.h \
 	ags/audio/ags_sound_provider.h \
 	ags/audio/ags_synth_generator.h \
-	ags/audio/ags_synth_util.h
+	ags/audio/ags_synth_util.h \
+	ags/audio/ags_wave.h
 
 deprecated_libags_audio_c_sources =
 
@@ -692,6 +697,7 @@ libags_audio_c_sources = \
 	ags/audio/ags_audio_connection.c \
 	ags/audio/ags_audio_signal.c \
 	ags/audio/ags_automation.c \
+	ags/audio/ags_buffer.c \
 	ags/audio/ags_channel.c \
 	ags/audio/ags_channel_iter.c \
 	ags/audio/ags_devout.c \
@@ -733,7 +739,8 @@ libags_audio_c_sources = \
 	ags/audio/ags_recycling_context.c \
 	ags/audio/ags_sound_provider.c \
 	ags/audio/ags_synth_generator.c \
-	ags/audio/ags_synth_util.c
+	ags/audio/ags_synth_util.c \
+	ags/audio/ags_wave.c
 
 # libags-audio - client
 deprecated_libags_audio_client_h_sources =
@@ -957,6 +964,8 @@ libags_audio_recall_h_sources = \
 	ags/audio/recall/ags_buffer_channel.h \
 	ags/audio/recall/ags_buffer_channel_run.h \
 	ags/audio/recall/ags_buffer_recycling.h \
+	ags/audio/recall/ags_capture_sound_audio.h \
+	ags/audio/recall/ags_capture_sound_audio_run.h \
 	ags/audio/recall/ags_copy_audio_signal.h \
 	ags/audio/recall/ags_copy_channel.h \
 	ags/audio/recall/ags_copy_channel_run.h \
@@ -1015,6 +1024,10 @@ libags_audio_recall_h_sources = \
 	ags/audio/recall/ags_route_dssi_audio_run.h \
 	ags/audio/recall/ags_route_lv2_audio.h \
 	ags/audio/recall/ags_route_lv2_audio_run.h \
+	ags/audio/recall/ags_rt_stream_audio_signal.h \
+	ags/audio/recall/ags_rt_stream_channel.h \
+	ags/audio/recall/ags_rt_stream_channel_run.h \
+	ags/audio/recall/ags_rt_stream_recycling.h \
 	ags/audio/recall/ags_stream_audio_signal.h \
 	ags/audio/recall/ags_stream_channel.h \
 	ags/audio/recall/ags_stream_channel_run.h \
@@ -1032,6 +1045,8 @@ libags_audio_recall_c_sources = \
 	ags/audio/recall/ags_buffer_channel.c \
 	ags/audio/recall/ags_buffer_channel_run.c \
 	ags/audio/recall/ags_buffer_recycling.c \
+	ags/audio/recall/ags_capture_sound_audio.c \
+	ags/audio/recall/ags_capture_sound_audio_run.c \
 	ags/audio/recall/ags_copy_audio_signal.c \
 	ags/audio/recall/ags_copy_channel.c \
 	ags/audio/recall/ags_copy_channel_run.c \
@@ -1090,6 +1105,10 @@ libags_audio_recall_c_sources = \
 	ags/audio/recall/ags_route_dssi_audio_run.c \
 	ags/audio/recall/ags_route_lv2_audio.c \
 	ags/audio/recall/ags_route_lv2_audio_run.c \
+	ags/audio/recall/ags_rt_stream_audio_signal.c \
+	ags/audio/recall/ags_rt_stream_channel.c \
+	ags/audio/recall/ags_rt_stream_channel_run.c \
+	ags/audio/recall/ags_rt_stream_recycling.c \
 	ags/audio/recall/ags_stream_audio_signal.c \
 	ags/audio/recall/ags_stream_channel.c \
 	ags/audio/recall/ags_stream_channel_run.c \
@@ -1247,6 +1266,10 @@ libags_gui_h_sources = \
 	ags/widget/ags_indicator.h \
 	ags/widget/ags_led.h \
 	ags/widget/ags_led_array.h \
+	ags/widget/ags_level.h \
+	ags/widget/ags_level_box.h \
+	ags/widget/ags_hlevel_box.h \
+	ags/widget/ags_vlevel_box.h \
 	ags/widget/ags_notebook.h \
 	ags/widget/ags_piano_keys.h \
 	ags/widget/ags_piano.h \
@@ -1255,6 +1278,7 @@ libags_gui_h_sources = \
 	ags/widget/ags_scale_box.h \
 	ags/widget/ags_vscale_box.h \
 	ags/widget/ags_hscale_box.h \
+	ags/widget/ags_scrolled_level_box.h \
 	ags/widget/ags_scrolled_scale_box.h \
 	ags/widget/ags_ruler.h \
 	ags/widget/ags_table.h \
@@ -1279,6 +1303,10 @@ libags_gui_c_sources = \
 	ags/widget/ags_indicator.c \
 	ags/widget/ags_led.c \
 	ags/widget/ags_led_array.c \
+	ags/widget/ags_level.c \
+	ags/widget/ags_level_box.c \
+	ags/widget/ags_hlevel_box.c \
+	ags/widget/ags_vlevel_box.c \
 	ags/widget/ags_notebook.c \
 	ags/widget/ags_piano.c \
 	ags/widget/ags_scrolled_piano.c \
@@ -1287,6 +1315,7 @@ libags_gui_c_sources = \
 	ags/widget/ags_vscale_box.c \
 	ags/widget/ags_hscale_box.c \
 	ags/widget/ags_scrolled_scale_box.c \
+	ags/widget/ags_scrolled_level_box.c \
 	ags/widget/ags_ruler.c \
 	ags/widget/ags_table.c \
 	ags/widget/ags_timebar.c \
@@ -1779,8 +1808,6 @@ libgsequencer_editor_h_sources = \
 	ags/X/editor/ags_file_selection.h \
 	ags/X/editor/ags_inline_player_callbacks.h \
 	ags/X/editor/ags_inline_player.h \
-	ags/X/editor/ags_level_callbacks.h \
-	ags/X/editor/ags_level.h \
 	ags/X/editor/ags_machine_radio_button.h \
 	ags/X/editor/ags_machine_radio_button_callbacks.h \
 	ags/X/editor/ags_machine_selection.h \
@@ -1801,6 +1828,7 @@ libgsequencer_editor_h_sources = \
 	ags/X/editor/ags_ramp_acceleration_dialog.h \
 	ags/X/editor/ags_ramp_acceleration_dialog_callbacks.h \
 	ags/X/editor/ags_scrolled_automation_edit_box.h \
+	ags/X/editor/ags_scrolled_wave_edit_box.h \
 	ags/X/editor/ags_sf2_chooser_callbacks.h \
 	ags/X/editor/ags_sf2_chooser.h \
 	ags/X/editor/ags_select_acceleration_dialog.h \
@@ -1808,8 +1836,10 @@ libgsequencer_editor_h_sources = \
 	ags/X/editor/ags_select_note_dialog.h \
 	ags/X/editor/ags_select_note_dialog_callbacks.h \
 	ags/X/editor/ags_vautomation_edit_box.h \
+	ags/X/editor/ags_vwave_edit_box.h \
 	ags/X/editor/ags_wave_edit_callbacks.h \
 	ags/X/editor/ags_wave_edit.h \
+	ags/X/editor/ags_wave_edit_box.h \
 	ags/X/editor/ags_wave_toolbar_callbacks.h \
 	ags/X/editor/ags_wave_toolbar.h
 
@@ -1834,8 +1864,6 @@ libgsequencer_editor_c_sources = \
 	ags/X/editor/ags_file_selection.c \
 	ags/X/editor/ags_inline_player.c \
 	ags/X/editor/ags_inline_player_callbacks.c \
-	ags/X/editor/ags_level.c \
-	ags/X/editor/ags_level_callbacks.c \
 	ags/X/editor/ags_machine_radio_button.c \
 	ags/X/editor/ags_machine_radio_button_callbacks.c \
 	ags/X/editor/ags_machine_selection.c \
@@ -1856,6 +1884,7 @@ libgsequencer_editor_c_sources = \
 	ags/X/editor/ags_ramp_acceleration_dialog.c \
 	ags/X/editor/ags_ramp_acceleration_dialog_callbacks.c \
 	ags/X/editor/ags_scrolled_automation_edit_box.c \
+	ags/X/editor/ags_scrolled_wave_edit_box.c \
 	ags/X/editor/ags_select_acceleration_dialog.c \
 	ags/X/editor/ags_select_acceleration_dialog_callbacks.c \
 	ags/X/editor/ags_select_note_dialog.c \
@@ -1863,7 +1892,9 @@ libgsequencer_editor_c_sources = \
 	ags/X/editor/ags_sf2_chooser.c \
 	ags/X/editor/ags_sf2_chooser_callbacks.c \
 	ags/X/editor/ags_vautomation_edit_box.c \
+	ags/X/editor/ags_vwave_edit_box.c \
 	ags/X/editor/ags_wave_edit.c \
+	ags/X/editor/ags_wave_edit_box.c \
 	ags/X/editor/ags_wave_edit_callbacks.c \
 	ags/X/editor/ags_wave_toolbar.c \
 	ags/X/editor/ags_wave_toolbar_callbacks.c
diff --git a/Makefile.in b/Makefile.in
index 0981ad9..2111f11 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -204,7 +204,8 @@ libags_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 	$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 am__objects_1 =
 am__dirstamp = $(am__leading_dot)dirstamp
-am__objects_2 = $(am__objects_1) ags/lib/libags_la-ags_complex.lo \
+am__objects_2 = $(am__objects_1) ags/lib/libags_la-ags_buffer_util.lo \
+	ags/lib/libags_la-ags_complex.lo \
 	ags/lib/libags_la-ags_conversion.lo \
 	ags/lib/libags_la-ags_endian.lo \
 	ags/lib/libags_la-ags_function.lo ags/lib/libags_la-ags_log.lo \
@@ -271,6 +272,7 @@ am__objects_6 = $(am__objects_1) \
 	ags/audio/libags_audio_la-ags_audio_connection.lo \
 	ags/audio/libags_audio_la-ags_audio_signal.lo \
 	ags/audio/libags_audio_la-ags_automation.lo \
+	ags/audio/libags_audio_la-ags_buffer.lo \
 	ags/audio/libags_audio_la-ags_channel.lo \
 	ags/audio/libags_audio_la-ags_channel_iter.lo \
 	ags/audio/libags_audio_la-ags_devout.lo \
@@ -312,7 +314,8 @@ am__objects_6 = $(am__objects_1) \
 	ags/audio/libags_audio_la-ags_recycling_context.lo \
 	ags/audio/libags_audio_la-ags_sound_provider.lo \
 	ags/audio/libags_audio_la-ags_synth_generator.lo \
-	ags/audio/libags_audio_la-ags_synth_util.lo
+	ags/audio/libags_audio_la-ags_synth_util.lo \
+	ags/audio/libags_audio_la-ags_wave.lo
 am__objects_7 = $(am__objects_1) \
 	ags/audio/client/libags_audio_la-ags_remote_channel.lo \
 	ags/audio/client/libags_audio_la-ags_remote_input.lo \
@@ -429,6 +432,8 @@ am__objects_15 = $(am__objects_1) \
 	ags/audio/recall/libags_audio_la-ags_buffer_channel.lo \
 	ags/audio/recall/libags_audio_la-ags_buffer_channel_run.lo \
 	ags/audio/recall/libags_audio_la-ags_buffer_recycling.lo \
+	ags/audio/recall/libags_audio_la-ags_capture_sound_audio.lo \
+	ags/audio/recall/libags_audio_la-ags_capture_sound_audio_run.lo \
 	ags/audio/recall/libags_audio_la-ags_copy_audio_signal.lo \
 	ags/audio/recall/libags_audio_la-ags_copy_channel.lo \
 	ags/audio/recall/libags_audio_la-ags_copy_channel_run.lo \
@@ -487,6 +492,10 @@ am__objects_15 = $(am__objects_1) \
 	ags/audio/recall/libags_audio_la-ags_route_dssi_audio_run.lo \
 	ags/audio/recall/libags_audio_la-ags_route_lv2_audio.lo \
 	ags/audio/recall/libags_audio_la-ags_route_lv2_audio_run.lo \
+	ags/audio/recall/libags_audio_la-ags_rt_stream_audio_signal.lo \
+	ags/audio/recall/libags_audio_la-ags_rt_stream_channel.lo \
+	ags/audio/recall/libags_audio_la-ags_rt_stream_channel_run.lo \
+	ags/audio/recall/libags_audio_la-ags_rt_stream_recycling.lo \
 	ags/audio/recall/libags_audio_la-ags_stream_audio_signal.lo \
 	ags/audio/recall/libags_audio_la-ags_stream_channel.lo \
 	ags/audio/recall/libags_audio_la-ags_stream_channel_run.lo \
@@ -539,6 +548,10 @@ am__objects_17 = $(am__objects_1) \
 	ags/widget/libags_gui_la-ags_indicator.lo \
 	ags/widget/libags_gui_la-ags_led.lo \
 	ags/widget/libags_gui_la-ags_led_array.lo \
+	ags/widget/libags_gui_la-ags_level.lo \
+	ags/widget/libags_gui_la-ags_level_box.lo \
+	ags/widget/libags_gui_la-ags_hlevel_box.lo \
+	ags/widget/libags_gui_la-ags_vlevel_box.lo \
 	ags/widget/libags_gui_la-ags_notebook.lo \
 	ags/widget/libags_gui_la-ags_piano.lo \
 	ags/widget/libags_gui_la-ags_scrolled_piano.lo \
@@ -547,6 +560,7 @@ am__objects_17 = $(am__objects_1) \
 	ags/widget/libags_gui_la-ags_vscale_box.lo \
 	ags/widget/libags_gui_la-ags_hscale_box.lo \
 	ags/widget/libags_gui_la-ags_scrolled_scale_box.lo \
+	ags/widget/libags_gui_la-ags_scrolled_level_box.lo \
 	ags/widget/libags_gui_la-ags_ruler.lo \
 	ags/widget/libags_gui_la-ags_table.lo \
 	ags/widget/libags_gui_la-ags_timebar.lo \
@@ -861,8 +875,6 @@ am__objects_33 = $(am__objects_1) \
 	ags/X/editor/libgsequencer_la-ags_file_selection.lo \
 	ags/X/editor/libgsequencer_la-ags_inline_player.lo \
 	ags/X/editor/libgsequencer_la-ags_inline_player_callbacks.lo \
-	ags/X/editor/libgsequencer_la-ags_level.lo \
-	ags/X/editor/libgsequencer_la-ags_level_callbacks.lo \
 	ags/X/editor/libgsequencer_la-ags_machine_radio_button.lo \
 	ags/X/editor/libgsequencer_la-ags_machine_radio_button_callbacks.lo \
 	ags/X/editor/libgsequencer_la-ags_machine_selection.lo \
@@ -883,6 +895,7 @@ am__objects_33 = $(am__objects_1) \
 	ags/X/editor/libgsequencer_la-ags_ramp_acceleration_dialog.lo \
 	ags/X/editor/libgsequencer_la-ags_ramp_acceleration_dialog_callbacks.lo \
 	ags/X/editor/libgsequencer_la-ags_scrolled_automation_edit_box.lo \
+	ags/X/editor/libgsequencer_la-ags_scrolled_wave_edit_box.lo \
 	ags/X/editor/libgsequencer_la-ags_select_acceleration_dialog.lo \
 	ags/X/editor/libgsequencer_la-ags_select_acceleration_dialog_callbacks.lo \
 	ags/X/editor/libgsequencer_la-ags_select_note_dialog.lo \
@@ -890,7 +903,9 @@ am__objects_33 = $(am__objects_1) \
 	ags/X/editor/libgsequencer_la-ags_sf2_chooser.lo \
 	ags/X/editor/libgsequencer_la-ags_sf2_chooser_callbacks.lo \
 	ags/X/editor/libgsequencer_la-ags_vautomation_edit_box.lo \
+	ags/X/editor/libgsequencer_la-ags_vwave_edit_box.lo \
 	ags/X/editor/libgsequencer_la-ags_wave_edit.lo \
+	ags/X/editor/libgsequencer_la-ags_wave_edit_box.lo \
 	ags/X/editor/libgsequencer_la-ags_wave_edit_callbacks.lo \
 	ags/X/editor/libgsequencer_la-ags_wave_toolbar.lo \
 	ags/X/editor/libgsequencer_la-ags_wave_toolbar_callbacks.lo
@@ -2192,6 +2207,7 @@ CAIRO_CFLAGS = @CAIRO_CFLAGS@
 CAIRO_LIBS = @CAIRO_LIBS@
 CC = @CC@
 CCDEPMODE = @CCDEPMODE@
+# -msse2 -O3 -ftree-vectorize -ftree-slp-vectorize -ffast-math -ftree-vectorizer-verbose=2
 
 # what flags you want to pass to the C compiler & linker
 CFLAGS = @CFLAGS@
@@ -3150,6 +3166,7 @@ noinst_HEADERS = ags/i18n.h
 deprecated_libags_h_sources = 
 libags_h_sources = \
 	$(deprecated_libags_h_sources) \
+	ags/lib/ags_buffer_util.h \
 	ags/lib/ags_complex.h \
 	ags/lib/ags_conversion.h \
 	ags/lib/ags_endian.h \
@@ -3165,6 +3182,7 @@ libags_h_sources = \
 deprecated_libags_c_sources = 
 libags_c_sources = \
 	$(deprecated_libags_c_sources) \
+	ags/lib/ags_buffer_util.c \
 	ags/lib/ags_complex.c \
 	ags/lib/ags_conversion.c \
 	ags/lib/ags_endian.c \
@@ -3453,6 +3471,7 @@ libags_audio_h_sources = \
 	ags/audio/ags_audio_connection.h \
 	ags/audio/ags_audio_signal.h \
 	ags/audio/ags_automation.h \
+	ags/audio/ags_buffer.h \
 	ags/audio/ags_channel.h \
 	ags/audio/ags_channel_iter.h \
 	ags/audio/ags_devout.h \
@@ -3495,7 +3514,8 @@ libags_audio_h_sources = \
 	ags/audio/ags_recycling.h \
 	ags/audio/ags_sound_provider.h \
 	ags/audio/ags_synth_generator.h \
-	ags/audio/ags_synth_util.h
+	ags/audio/ags_synth_util.h \
+	ags/audio/ags_wave.h
 
 deprecated_libags_audio_c_sources = 
 libags_audio_c_sources = \
@@ -3507,6 +3527,7 @@ libags_audio_c_sources = \
 	ags/audio/ags_audio_connection.c \
 	ags/audio/ags_audio_signal.c \
 	ags/audio/ags_automation.c \
+	ags/audio/ags_buffer.c \
 	ags/audio/ags_channel.c \
 	ags/audio/ags_channel_iter.c \
 	ags/audio/ags_devout.c \
@@ -3548,7 +3569,8 @@ libags_audio_c_sources = \
 	ags/audio/ags_recycling_context.c \
 	ags/audio/ags_sound_provider.c \
 	ags/audio/ags_synth_generator.c \
-	ags/audio/ags_synth_util.c
+	ags/audio/ags_synth_util.c \
+	ags/audio/ags_wave.c
 
 
 # libags-audio - client
@@ -3764,6 +3786,8 @@ libags_audio_recall_h_sources = \
 	ags/audio/recall/ags_buffer_channel.h \
 	ags/audio/recall/ags_buffer_channel_run.h \
 	ags/audio/recall/ags_buffer_recycling.h \
+	ags/audio/recall/ags_capture_sound_audio.h \
+	ags/audio/recall/ags_capture_sound_audio_run.h \
 	ags/audio/recall/ags_copy_audio_signal.h \
 	ags/audio/recall/ags_copy_channel.h \
 	ags/audio/recall/ags_copy_channel_run.h \
@@ -3822,6 +3846,10 @@ libags_audio_recall_h_sources = \
 	ags/audio/recall/ags_route_dssi_audio_run.h \
 	ags/audio/recall/ags_route_lv2_audio.h \
 	ags/audio/recall/ags_route_lv2_audio_run.h \
+	ags/audio/recall/ags_rt_stream_audio_signal.h \
+	ags/audio/recall/ags_rt_stream_channel.h \
+	ags/audio/recall/ags_rt_stream_channel_run.h \
+	ags/audio/recall/ags_rt_stream_recycling.h \
 	ags/audio/recall/ags_stream_audio_signal.h \
 	ags/audio/recall/ags_stream_channel.h \
 	ags/audio/recall/ags_stream_channel_run.h \
@@ -3838,6 +3866,8 @@ libags_audio_recall_c_sources = \
 	ags/audio/recall/ags_buffer_channel.c \
 	ags/audio/recall/ags_buffer_channel_run.c \
 	ags/audio/recall/ags_buffer_recycling.c \
+	ags/audio/recall/ags_capture_sound_audio.c \
+	ags/audio/recall/ags_capture_sound_audio_run.c \
 	ags/audio/recall/ags_copy_audio_signal.c \
 	ags/audio/recall/ags_copy_channel.c \
 	ags/audio/recall/ags_copy_channel_run.c \
@@ -3896,6 +3926,10 @@ libags_audio_recall_c_sources = \
 	ags/audio/recall/ags_route_dssi_audio_run.c \
 	ags/audio/recall/ags_route_lv2_audio.c \
 	ags/audio/recall/ags_route_lv2_audio_run.c \
+	ags/audio/recall/ags_rt_stream_audio_signal.c \
+	ags/audio/recall/ags_rt_stream_channel.c \
+	ags/audio/recall/ags_rt_stream_channel_run.c \
+	ags/audio/recall/ags_rt_stream_recycling.c \
 	ags/audio/recall/ags_stream_audio_signal.c \
 	ags/audio/recall/ags_stream_channel.c \
 	ags/audio/recall/ags_stream_channel_run.c \
@@ -4052,6 +4086,10 @@ libags_gui_h_sources = \
 	ags/widget/ags_indicator.h \
 	ags/widget/ags_led.h \
 	ags/widget/ags_led_array.h \
+	ags/widget/ags_level.h \
+	ags/widget/ags_level_box.h \
+	ags/widget/ags_hlevel_box.h \
+	ags/widget/ags_vlevel_box.h \
 	ags/widget/ags_notebook.h \
 	ags/widget/ags_piano_keys.h \
 	ags/widget/ags_piano.h \
@@ -4060,6 +4098,7 @@ libags_gui_h_sources = \
 	ags/widget/ags_scale_box.h \
 	ags/widget/ags_vscale_box.h \
 	ags/widget/ags_hscale_box.h \
+	ags/widget/ags_scrolled_level_box.h \
 	ags/widget/ags_scrolled_scale_box.h \
 	ags/widget/ags_ruler.h \
 	ags/widget/ags_table.h \
@@ -4083,6 +4122,10 @@ libags_gui_c_sources = \
 	ags/widget/ags_indicator.c \
 	ags/widget/ags_led.c \
 	ags/widget/ags_led_array.c \
+	ags/widget/ags_level.c \
+	ags/widget/ags_level_box.c \
+	ags/widget/ags_hlevel_box.c \
+	ags/widget/ags_vlevel_box.c \
 	ags/widget/ags_notebook.c \
 	ags/widget/ags_piano.c \
 	ags/widget/ags_scrolled_piano.c \
@@ -4091,6 +4134,7 @@ libags_gui_c_sources = \
 	ags/widget/ags_vscale_box.c \
 	ags/widget/ags_hscale_box.c \
 	ags/widget/ags_scrolled_scale_box.c \
+	ags/widget/ags_scrolled_level_box.c \
 	ags/widget/ags_ruler.c \
 	ags/widget/ags_table.c \
 	ags/widget/ags_timebar.c \
@@ -4576,8 +4620,6 @@ libgsequencer_editor_h_sources = \
 	ags/X/editor/ags_file_selection.h \
 	ags/X/editor/ags_inline_player_callbacks.h \
 	ags/X/editor/ags_inline_player.h \
-	ags/X/editor/ags_level_callbacks.h \
-	ags/X/editor/ags_level.h \
 	ags/X/editor/ags_machine_radio_button.h \
 	ags/X/editor/ags_machine_radio_button_callbacks.h \
 	ags/X/editor/ags_machine_selection.h \
@@ -4598,6 +4640,7 @@ libgsequencer_editor_h_sources = \
 	ags/X/editor/ags_ramp_acceleration_dialog.h \
 	ags/X/editor/ags_ramp_acceleration_dialog_callbacks.h \
 	ags/X/editor/ags_scrolled_automation_edit_box.h \
+	ags/X/editor/ags_scrolled_wave_edit_box.h \
 	ags/X/editor/ags_sf2_chooser_callbacks.h \
 	ags/X/editor/ags_sf2_chooser.h \
 	ags/X/editor/ags_select_acceleration_dialog.h \
@@ -4605,8 +4648,10 @@ libgsequencer_editor_h_sources = \
 	ags/X/editor/ags_select_note_dialog.h \
 	ags/X/editor/ags_select_note_dialog_callbacks.h \
 	ags/X/editor/ags_vautomation_edit_box.h \
+	ags/X/editor/ags_vwave_edit_box.h \
 	ags/X/editor/ags_wave_edit_callbacks.h \
 	ags/X/editor/ags_wave_edit.h \
+	ags/X/editor/ags_wave_edit_box.h \
 	ags/X/editor/ags_wave_toolbar_callbacks.h \
 	ags/X/editor/ags_wave_toolbar.h
 
@@ -4630,8 +4675,6 @@ libgsequencer_editor_c_sources = \
 	ags/X/editor/ags_file_selection.c \
 	ags/X/editor/ags_inline_player.c \
 	ags/X/editor/ags_inline_player_callbacks.c \
-	ags/X/editor/ags_level.c \
-	ags/X/editor/ags_level_callbacks.c \
 	ags/X/editor/ags_machine_radio_button.c \
 	ags/X/editor/ags_machine_radio_button_callbacks.c \
 	ags/X/editor/ags_machine_selection.c \
@@ -4652,6 +4695,7 @@ libgsequencer_editor_c_sources = \
 	ags/X/editor/ags_ramp_acceleration_dialog.c \
 	ags/X/editor/ags_ramp_acceleration_dialog_callbacks.c \
 	ags/X/editor/ags_scrolled_automation_edit_box.c \
+	ags/X/editor/ags_scrolled_wave_edit_box.c \
 	ags/X/editor/ags_select_acceleration_dialog.c \
 	ags/X/editor/ags_select_acceleration_dialog_callbacks.c \
 	ags/X/editor/ags_select_note_dialog.c \
@@ -4659,7 +4703,9 @@ libgsequencer_editor_c_sources = \
 	ags/X/editor/ags_sf2_chooser.c \
 	ags/X/editor/ags_sf2_chooser_callbacks.c \
 	ags/X/editor/ags_vautomation_edit_box.c \
+	ags/X/editor/ags_vwave_edit_box.c \
 	ags/X/editor/ags_wave_edit.c \
+	ags/X/editor/ags_wave_edit_box.c \
 	ags/X/editor/ags_wave_edit_callbacks.c \
 	ags/X/editor/ags_wave_toolbar.c \
 	ags/X/editor/ags_wave_toolbar_callbacks.c
@@ -4822,6 +4868,8 @@ ags/lib/$(am__dirstamp):
 ags/lib/$(DEPDIR)/$(am__dirstamp):
 	@$(MKDIR_P) ags/lib/$(DEPDIR)
 	@: > ags/lib/$(DEPDIR)/$(am__dirstamp)
+ags/lib/libags_la-ags_buffer_util.lo: ags/lib/$(am__dirstamp) \
+	ags/lib/$(DEPDIR)/$(am__dirstamp)
 ags/lib/libags_la-ags_complex.lo: ags/lib/$(am__dirstamp) \
 	ags/lib/$(DEPDIR)/$(am__dirstamp)
 ags/lib/libags_la-ags_conversion.lo: ags/lib/$(am__dirstamp) \
@@ -4954,6 +5002,8 @@ ags/audio/libags_audio_la-ags_audio_signal.lo:  \
 	ags/audio/$(am__dirstamp) ags/audio/$(DEPDIR)/$(am__dirstamp)
 ags/audio/libags_audio_la-ags_automation.lo:  \
 	ags/audio/$(am__dirstamp) ags/audio/$(DEPDIR)/$(am__dirstamp)
+ags/audio/libags_audio_la-ags_buffer.lo: ags/audio/$(am__dirstamp) \
+	ags/audio/$(DEPDIR)/$(am__dirstamp)
 ags/audio/libags_audio_la-ags_channel.lo: ags/audio/$(am__dirstamp) \
 	ags/audio/$(DEPDIR)/$(am__dirstamp)
 ags/audio/libags_audio_la-ags_channel_iter.lo:  \
@@ -5038,6 +5088,8 @@ ags/audio/libags_audio_la-ags_synth_generator.lo:  \
 	ags/audio/$(am__dirstamp) ags/audio/$(DEPDIR)/$(am__dirstamp)
 ags/audio/libags_audio_la-ags_synth_util.lo:  \
 	ags/audio/$(am__dirstamp) ags/audio/$(DEPDIR)/$(am__dirstamp)
+ags/audio/libags_audio_la-ags_wave.lo: ags/audio/$(am__dirstamp) \
+	ags/audio/$(DEPDIR)/$(am__dirstamp)
 ags/audio/client/$(am__dirstamp):
 	@$(MKDIR_P) ags/audio/client
 	@: > ags/audio/client/$(am__dirstamp)
@@ -5419,6 +5471,12 @@ ags/audio/recall/libags_audio_la-ags_buffer_channel_run.lo:  \
 ags/audio/recall/libags_audio_la-ags_buffer_recycling.lo:  \
 	ags/audio/recall/$(am__dirstamp) \
 	ags/audio/recall/$(DEPDIR)/$(am__dirstamp)
+ags/audio/recall/libags_audio_la-ags_capture_sound_audio.lo:  \
+	ags/audio/recall/$(am__dirstamp) \
+	ags/audio/recall/$(DEPDIR)/$(am__dirstamp)
+ags/audio/recall/libags_audio_la-ags_capture_sound_audio_run.lo:  \
+	ags/audio/recall/$(am__dirstamp) \
+	ags/audio/recall/$(DEPDIR)/$(am__dirstamp)
 ags/audio/recall/libags_audio_la-ags_copy_audio_signal.lo:  \
 	ags/audio/recall/$(am__dirstamp) \
 	ags/audio/recall/$(DEPDIR)/$(am__dirstamp)
@@ -5593,6 +5651,18 @@ ags/audio/recall/libags_audio_la-ags_route_lv2_audio.lo:  \
 ags/audio/recall/libags_audio_la-ags_route_lv2_audio_run.lo:  \
 	ags/audio/recall/$(am__dirstamp) \
 	ags/audio/recall/$(DEPDIR)/$(am__dirstamp)
+ags/audio/recall/libags_audio_la-ags_rt_stream_audio_signal.lo:  \
+	ags/audio/recall/$(am__dirstamp) \
+	ags/audio/recall/$(DEPDIR)/$(am__dirstamp)
+ags/audio/recall/libags_audio_la-ags_rt_stream_channel.lo:  \
+	ags/audio/recall/$(am__dirstamp) \
+	ags/audio/recall/$(DEPDIR)/$(am__dirstamp)
+ags/audio/recall/libags_audio_la-ags_rt_stream_channel_run.lo:  \
+	ags/audio/recall/$(am__dirstamp) \
+	ags/audio/recall/$(DEPDIR)/$(am__dirstamp)
+ags/audio/recall/libags_audio_la-ags_rt_stream_recycling.lo:  \
+	ags/audio/recall/$(am__dirstamp) \
+	ags/audio/recall/$(DEPDIR)/$(am__dirstamp)
 ags/audio/recall/libags_audio_la-ags_stream_audio_signal.lo:  \
 	ags/audio/recall/$(am__dirstamp) \
 	ags/audio/recall/$(DEPDIR)/$(am__dirstamp)
@@ -5715,6 +5785,16 @@ ags/widget/libags_gui_la-ags_led.lo: ags/widget/$(am__dirstamp) \
 	ags/widget/$(DEPDIR)/$(am__dirstamp)
 ags/widget/libags_gui_la-ags_led_array.lo: ags/widget/$(am__dirstamp) \
 	ags/widget/$(DEPDIR)/$(am__dirstamp)
+ags/widget/libags_gui_la-ags_level.lo: ags/widget/$(am__dirstamp) \
+	ags/widget/$(DEPDIR)/$(am__dirstamp)
+ags/widget/libags_gui_la-ags_level_box.lo: ags/widget/$(am__dirstamp) \
+	ags/widget/$(DEPDIR)/$(am__dirstamp)
+ags/widget/libags_gui_la-ags_hlevel_box.lo:  \
+	ags/widget/$(am__dirstamp) \
+	ags/widget/$(DEPDIR)/$(am__dirstamp)
+ags/widget/libags_gui_la-ags_vlevel_box.lo:  \
+	ags/widget/$(am__dirstamp) \
+	ags/widget/$(DEPDIR)/$(am__dirstamp)
 ags/widget/libags_gui_la-ags_notebook.lo: ags/widget/$(am__dirstamp) \
 	ags/widget/$(DEPDIR)/$(am__dirstamp)
 ags/widget/libags_gui_la-ags_piano.lo: ags/widget/$(am__dirstamp) \
@@ -5735,6 +5815,9 @@ ags/widget/libags_gui_la-ags_hscale_box.lo:  \
 ags/widget/libags_gui_la-ags_scrolled_scale_box.lo:  \
 	ags/widget/$(am__dirstamp) \
 	ags/widget/$(DEPDIR)/$(am__dirstamp)
+ags/widget/libags_gui_la-ags_scrolled_level_box.lo:  \
+	ags/widget/$(am__dirstamp) \
+	ags/widget/$(DEPDIR)/$(am__dirstamp)
 ags/widget/libags_gui_la-ags_ruler.lo: ags/widget/$(am__dirstamp) \
 	ags/widget/$(DEPDIR)/$(am__dirstamp)
 ags/widget/libags_gui_la-ags_table.lo: ags/widget/$(am__dirstamp) \
@@ -6517,12 +6600,6 @@ ags/X/editor/libgsequencer_la-ags_inline_player.lo:  \
 ags/X/editor/libgsequencer_la-ags_inline_player_callbacks.lo:  \
 	ags/X/editor/$(am__dirstamp) \
 	ags/X/editor/$(DEPDIR)/$(am__dirstamp)
-ags/X/editor/libgsequencer_la-ags_level.lo:  \
-	ags/X/editor/$(am__dirstamp) \
-	ags/X/editor/$(DEPDIR)/$(am__dirstamp)
-ags/X/editor/libgsequencer_la-ags_level_callbacks.lo:  \
-	ags/X/editor/$(am__dirstamp) \
-	ags/X/editor/$(DEPDIR)/$(am__dirstamp)
 ags/X/editor/libgsequencer_la-ags_machine_radio_button.lo:  \
 	ags/X/editor/$(am__dirstamp) \
 	ags/X/editor/$(DEPDIR)/$(am__dirstamp)
@@ -6583,6 +6660,9 @@ ags/X/editor/libgsequencer_la-ags_ramp_acceleration_dialog_callbacks.lo:  \
 ags/X/editor/libgsequencer_la-ags_scrolled_automation_edit_box.lo:  \
 	ags/X/editor/$(am__dirstamp) \
 	ags/X/editor/$(DEPDIR)/$(am__dirstamp)
+ags/X/editor/libgsequencer_la-ags_scrolled_wave_edit_box.lo:  \
+	ags/X/editor/$(am__dirstamp) \
+	ags/X/editor/$(DEPDIR)/$(am__dirstamp)
 ags/X/editor/libgsequencer_la-ags_select_acceleration_dialog.lo:  \
 	ags/X/editor/$(am__dirstamp) \
 	ags/X/editor/$(DEPDIR)/$(am__dirstamp)
@@ -6604,9 +6684,15 @@ ags/X/editor/libgsequencer_la-ags_sf2_chooser_callbacks.lo:  \
 ags/X/editor/libgsequencer_la-ags_vautomation_edit_box.lo:  \
 	ags/X/editor/$(am__dirstamp) \
 	ags/X/editor/$(DEPDIR)/$(am__dirstamp)
+ags/X/editor/libgsequencer_la-ags_vwave_edit_box.lo:  \
+	ags/X/editor/$(am__dirstamp) \
+	ags/X/editor/$(DEPDIR)/$(am__dirstamp)
 ags/X/editor/libgsequencer_la-ags_wave_edit.lo:  \
 	ags/X/editor/$(am__dirstamp) \
 	ags/X/editor/$(DEPDIR)/$(am__dirstamp)
+ags/X/editor/libgsequencer_la-ags_wave_edit_box.lo:  \
+	ags/X/editor/$(am__dirstamp) \
+	ags/X/editor/$(DEPDIR)/$(am__dirstamp)
 ags/X/editor/libgsequencer_la-ags_wave_edit_callbacks.lo:  \
 	ags/X/editor/$(am__dirstamp) \
 	ags/X/editor/$(DEPDIR)/$(am__dirstamp)
@@ -7491,8 +7577,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_file_selection_callbacks.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_inline_player.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_inline_player_callbacks.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_level.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_level_callbacks.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_machine_radio_button.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_machine_radio_button_callbacks.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_machine_selection.Plo at am__quote@
@@ -7513,6 +7597,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_ramp_acceleration_dialog.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_ramp_acceleration_dialog_callbacks.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_scrolled_automation_edit_box.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_scrolled_wave_edit_box.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_select_acceleration_dialog.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_select_acceleration_dialog_callbacks.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_select_note_dialog.Plo at am__quote@
@@ -7520,7 +7605,9 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_sf2_chooser.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_sf2_chooser_callbacks.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_vautomation_edit_box.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_vwave_edit_box.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_wave_edit.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_wave_edit_box.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_wave_edit_callbacks.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_wave_toolbar.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_wave_toolbar_callbacks.Plo at am__quote@
@@ -7621,6 +7708,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/$(DEPDIR)/libags_audio_la-ags_audio_connection.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/$(DEPDIR)/libags_audio_la-ags_audio_signal.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/$(DEPDIR)/libags_audio_la-ags_automation.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/audio/$(DEPDIR)/libags_audio_la-ags_buffer.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/$(DEPDIR)/libags_audio_la-ags_channel.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/$(DEPDIR)/libags_audio_la-ags_channel_iter.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/$(DEPDIR)/libags_audio_la-ags_devin.Plo at am__quote@
@@ -7663,6 +7751,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/$(DEPDIR)/libags_audio_la-ags_sound_provider.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/$(DEPDIR)/libags_audio_la-ags_synth_generator.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/$(DEPDIR)/libags_audio_la-ags_synth_util.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/audio/$(DEPDIR)/libags_audio_la-ags_wave.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/client/$(DEPDIR)/libags_audio_la-ags_remote_channel.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/client/$(DEPDIR)/libags_audio_la-ags_remote_input.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/client/$(DEPDIR)/libags_audio_la-ags_remote_output.Plo at am__quote@
@@ -7699,6 +7788,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_buffer_channel.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_buffer_channel_run.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_buffer_recycling.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_capture_sound_audio.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_capture_sound_audio_run.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_copy_audio_signal.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_copy_channel.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_copy_channel_run.Plo at am__quote@
@@ -7757,6 +7848,10 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_route_dssi_audio_run.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_route_lv2_audio.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_route_lv2_audio_run.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_rt_stream_audio_signal.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_rt_stream_channel.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_rt_stream_channel_run.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_rt_stream_recycling.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_stream_audio_signal.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_stream_channel.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_stream_channel_run.Plo at am__quote@
@@ -7843,6 +7938,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ags/file/$(DEPDIR)/libags_la-ags_file_lookup.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/file/$(DEPDIR)/libags_la-ags_file_util.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/file/$(DEPDIR)/libags_la-ags_xml_serialization_factory.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/lib/$(DEPDIR)/libags_la-ags_buffer_util.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/lib/$(DEPDIR)/libags_la-ags_complex.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/lib/$(DEPDIR)/libags_la-ags_conversion.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/lib/$(DEPDIR)/libags_la-ags_endian.Plo at am__quote@
@@ -8032,22 +8128,27 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_expander_set.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_hindicator.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_hled_array.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_hlevel_box.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_hscale_box.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_htimebar.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_indicator.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_led.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_led_array.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_level.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_level_box.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_notebook.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_piano.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_ruler.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_scale.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_scale_box.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_scrolled_level_box.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_scrolled_piano.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_scrolled_scale_box.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_table.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_timebar.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_vindicator.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_vled_array.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_vlevel_box.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_vscale_box.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_waveform.Plo at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at ags/widget/$(DEPDIR)/libags_gui_la-ags_widget_marshal.Plo at am__quote@
@@ -8076,6 +8177,13 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
+ags/lib/libags_la-ags_buffer_util.lo: ags/lib/ags_buffer_util.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_la_CFLAGS) $(CFLAGS) -MT ags/lib/libags_la-ags_buffer_util.lo -MD -MP -MF ags/lib/$(DEPDIR)/libags_la-ags_buffer_util.Tpo -c -o ags/lib/libags_la-ags_buffer_util.lo `test -f 'ags/lib/ags_buffer_util.c' || echo '$(srcdir)/'`ags/lib/ags_buffer_util.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/lib/$(DEPDIR)/libags_la-ags_buffer_util.Tpo ags/lib/$(DEPDIR)/libags_la-ags_buffer_util.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/lib/ags_buffer_util.c' object='ags/lib/libags_la-ags_buffer_util.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_la_CFLAGS) $(CFLAGS) -c -o ags/lib/libags_la-ags_buffer_util.lo `test -f 'ags/lib/ags_buffer_util.c' || echo '$(srcdir)/'`ags/lib/ags_buffer_util.c
+
 ags/lib/libags_la-ags_complex.lo: ags/lib/ags_complex.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_la_CFLAGS) $(CFLAGS) -MT ags/lib/libags_la-ags_complex.lo -MD -MP -MF ags/lib/$(DEPDIR)/libags_la-ags_complex.Tpo -c -o ags/lib/libags_la-ags_complex.lo `test -f 'ags/lib/ags_complex.c' || echo '$(srcdir)/'`ags/lib/ags_complex.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/lib/$(DEPDIR)/libags_la-ags_complex.Tpo ags/lib/$(DEPDIR)/libags_la-ags_complex.Plo
@@ -8426,6 +8534,13 @@ ags/audio/libags_audio_la-ags_automation.lo: ags/audio/ags_automation.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -c -o ags/audio/libags_audio_la-ags_automation.lo `test -f 'ags/audio/ags_automation.c' || echo '$(srcdir)/'`ags/audio/ags_automation.c
 
+ags/audio/libags_audio_la-ags_buffer.lo: ags/audio/ags_buffer.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -MT ags/audio/libags_audio_la-ags_buffer.lo -MD -MP -MF ags/audio/$(DEPDIR)/libags_audio_la-ags_buffer.Tpo -c -o ags/audio/libags_audio_la-ags_buffer.lo `test -f 'ags/audio/ags_buffer.c' || echo '$(srcdir)/'`ags/audio/ags_buffer.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/audio/$(DEPDIR)/libags_audio_la-ags_buffer.Tpo ags/audio/$(DEPDIR)/libags_audio_la-ags_buffer.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/audio/ags_buffer.c' object='ags/audio/libags_audio_la-ags_buffer.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -c -o ags/audio/libags_audio_la-ags_buffer.lo `test -f 'ags/audio/ags_buffer.c' || echo '$(srcdir)/'`ags/audio/ags_buffer.c
+
 ags/audio/libags_audio_la-ags_channel.lo: ags/audio/ags_channel.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -MT ags/audio/libags_audio_la-ags_channel.lo -MD -MP -MF ags/audio/$(DEPDIR)/libags_audio_la-ags_channel.Tpo -c -o ags/audio/libags_audio_la-ags_channel.lo `test -f 'ags/audio/ags_channel.c' || echo '$(srcdir)/'`ags/audio/ags_channel.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/audio/$(DEPDIR)/libags_audio_la-ags_channel.Tpo ags/audio/$(DEPDIR)/libags_audio_la-ags_channel.Plo
@@ -8720,6 +8835,13 @@ ags/audio/libags_audio_la-ags_synth_util.lo: ags/audio/ags_synth_util.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -c -o ags/audio/libags_audio_la-ags_synth_util.lo `test -f 'ags/audio/ags_synth_util.c' || echo '$(srcdir)/'`ags/audio/ags_synth_util.c
 
+ags/audio/libags_audio_la-ags_wave.lo: ags/audio/ags_wave.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -MT ags/audio/libags_audio_la-ags_wave.lo -MD -MP -MF ags/audio/$(DEPDIR)/libags_audio_la-ags_wave.Tpo -c -o ags/audio/libags_audio_la-ags_wave.lo `test -f 'ags/audio/ags_wave.c' || echo '$(srcdir)/'`ags/audio/ags_wave.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/audio/$(DEPDIR)/libags_audio_la-ags_wave.Tpo ags/audio/$(DEPDIR)/libags_audio_la-ags_wave.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/audio/ags_wave.c' object='ags/audio/libags_audio_la-ags_wave.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -c -o ags/audio/libags_audio_la-ags_wave.lo `test -f 'ags/audio/ags_wave.c' || echo '$(srcdir)/'`ags/audio/ags_wave.c
+
 ags/audio/client/libags_audio_la-ags_remote_channel.lo: ags/audio/client/ags_remote_channel.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -MT ags/audio/client/libags_audio_la-ags_remote_channel.lo -MD -MP -MF ags/audio/client/$(DEPDIR)/libags_audio_la-ags_remote_channel.Tpo -c -o ags/audio/client/libags_audio_la-ags_remote_channel.lo `test -f 'ags/audio/client/ags_remote_channel.c' || echo '$(srcdir)/'`ags/audio/client/ags_remote_channel.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/audio/client/$(DEPDIR)/libags_audio_la-ags_remote_channel.Tpo ags/audio/client/$(DEPDIR)/libags_audio_la-ags_remote_channel.Plo
@@ -9469,6 +9591,20 @@ ags/audio/recall/libags_audio_la-ags_buffer_recycling.lo: ags/audio/recall/ags_b
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -c -o ags/audio/recall/libags_audio_la-ags_buffer_recycling.lo `test -f 'ags/audio/recall/ags_buffer_recycling.c' || echo '$(srcdir)/'`ags/audio/recall/ags_buffer_recycling.c
 
+ags/audio/recall/libags_audio_la-ags_capture_sound_audio.lo: ags/audio/recall/ags_capture_sound_audio.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -MT ags/audio/recall/libags_audio_la-ags_capture_sound_audio.lo -MD -MP -MF ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_capture_sound_audio.Tpo -c -o ags/audio/recall/libags_audio_la-ags_capture_sound_audio.lo `test -f 'ags/audio/recall/ags_capture_sound_audio.c' || echo '$(srcdir)/'`ags/audio/recall/ags_capture_sound_audio.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_capture_sound_audio.Tpo ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_capture_sound_audio.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/audio/recall/ags_capture_sound_audio.c' object='ags/audio/recall/libags_audio_la-ags_capture_sound_audio.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -c -o ags/audio/recall/libags_audio_la-ags_capture_sound_audio.lo `test -f 'ags/audio/recall/ags_capture_sound_audio.c' || echo '$(srcdir)/'`ags/audio/recall/ags_capture_sound_audio.c
+
+ags/audio/recall/libags_audio_la-ags_capture_sound_audio_run.lo: ags/audio/recall/ags_capture_sound_audio_run.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -MT ags/audio/recall/libags_audio_la-ags_capture_sound_audio_run.lo -MD -MP -MF ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_capture_sound_audio_run.Tpo -c -o ags/audio/recall/libags_audio_la-ags_capture_sound_audio_run.lo `test -f 'ags/audio/recall/ags_capture_sound_audio_run.c' || echo '$(srcdir)/'`ags/audio/recall/ags_capture_sound_audio_run.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_capture_sound_audio_run.Tpo ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_capture_sound_audio_run.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/audio/recall/ags_capture_sound_audio_run.c' object='ags/audio/recall/libags_audio_la-ags_capture_sound_audio_run.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -c -o ags/audio/recall/libags_audio_la-ags_capture_sound_audio_run.lo `test -f 'ags/audio/recall/ags_capture_sound_audio_run.c' || echo '$(srcdir)/'`ags/audio/recall/ags_capture_sound_audio_run.c
+
 ags/audio/recall/libags_audio_la-ags_copy_audio_signal.lo: ags/audio/recall/ags_copy_audio_signal.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -MT ags/audio/recall/libags_audio_la-ags_copy_audio_signal.lo -MD -MP -MF ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_copy_audio_signal.Tpo -c -o ags/audio/recall/libags_audio_la-ags_copy_audio_signal.lo `test -f 'ags/audio/recall/ags_copy_audio_signal.c' || echo '$(srcdir)/'`ags/audio/recall/ags_copy_audio_signal.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_copy_audio_signal.Tpo ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_copy_audio_signal.Plo
@@ -9875,6 +10011,34 @@ ags/audio/recall/libags_audio_la-ags_route_lv2_audio_run.lo: ags/audio/recall/ag
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -c -o ags/audio/recall/libags_audio_la-ags_route_lv2_audio_run.lo `test -f 'ags/audio/recall/ags_route_lv2_audio_run.c' || echo '$(srcdir)/'`ags/audio/recall/ags_route_lv2_audio_run.c
 
+ags/audio/recall/libags_audio_la-ags_rt_stream_audio_signal.lo: ags/audio/recall/ags_rt_stream_audio_signal.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -MT ags/audio/recall/libags_audio_la-ags_rt_stream_audio_signal.lo -MD -MP -MF ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_rt_stream_audio_signal.Tpo -c -o ags/audio/recall/libags_audio_la-ags_rt_stream_audio_signal.lo `test -f 'ags/audio/recall/ags_rt_stream_audio_signal.c' || echo '$(srcdir)/'`ags/audio/recall/ags_rt_stream_audio_signal.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_rt_stream_audio_signal.Tpo ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_rt_stream_audio_signal.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/audio/recall/ags_rt_stream_audio_signal.c' object='ags/audio/recall/libags_audio_la-ags_rt_stream_audio_signal.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -c -o ags/audio/recall/libags_audio_la-ags_rt_stream_audio_signal.lo `test -f 'ags/audio/recall/ags_rt_stream_audio_signal.c' || echo '$(srcdir)/'`ags/audio/recall/ags_rt_stream_audio_signal.c
+
+ags/audio/recall/libags_audio_la-ags_rt_stream_channel.lo: ags/audio/recall/ags_rt_stream_channel.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -MT ags/audio/recall/libags_audio_la-ags_rt_stream_channel.lo -MD -MP -MF ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_rt_stream_channel.Tpo -c -o ags/audio/recall/libags_audio_la-ags_rt_stream_channel.lo `test -f 'ags/audio/recall/ags_rt_stream_channel.c' || echo '$(srcdir)/'`ags/audio/recall/ags_rt_stream_channel.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_rt_stream_channel.Tpo ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_rt_stream_channel.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/audio/recall/ags_rt_stream_channel.c' object='ags/audio/recall/libags_audio_la-ags_rt_stream_channel.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -c -o ags/audio/recall/libags_audio_la-ags_rt_stream_channel.lo `test -f 'ags/audio/recall/ags_rt_stream_channel.c' || echo '$(srcdir)/'`ags/audio/recall/ags_rt_stream_channel.c
+
+ags/audio/recall/libags_audio_la-ags_rt_stream_channel_run.lo: ags/audio/recall/ags_rt_stream_channel_run.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -MT ags/audio/recall/libags_audio_la-ags_rt_stream_channel_run.lo -MD -MP -MF ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_rt_stream_channel_run.Tpo -c -o ags/audio/recall/libags_audio_la-ags_rt_stream_channel_run.lo `test -f 'ags/audio/recall/ags_rt_stream_channel_run.c' || echo '$(srcdir)/'`ags/audio/recall/ags_rt_stream_channel_run.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_rt_stream_channel_run.Tpo ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_rt_stream_channel_run.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/audio/recall/ags_rt_stream_channel_run.c' object='ags/audio/recall/libags_audio_la-ags_rt_stream_channel_run.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -c -o ags/audio/recall/libags_audio_la-ags_rt_stream_channel_run.lo `test -f 'ags/audio/recall/ags_rt_stream_channel_run.c' || echo '$(srcdir)/'`ags/audio/recall/ags_rt_stream_channel_run.c
+
+ags/audio/recall/libags_audio_la-ags_rt_stream_recycling.lo: ags/audio/recall/ags_rt_stream_recycling.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -MT ags/audio/recall/libags_audio_la-ags_rt_stream_recycling.lo -MD -MP -MF ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_rt_stream_recycling.Tpo -c -o ags/audio/recall/libags_audio_la-ags_rt_stream_recycling.lo `test -f 'ags/audio/recall/ags_rt_stream_recycling.c' || echo '$(srcdir)/'`ags/audio/recall/ags_rt_stream_recycling.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_rt_stream_recycling.Tpo ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_rt_stream_recycling.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/audio/recall/ags_rt_stream_recycling.c' object='ags/audio/recall/libags_audio_la-ags_rt_stream_recycling.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -c -o ags/audio/recall/libags_audio_la-ags_rt_stream_recycling.lo `test -f 'ags/audio/recall/ags_rt_stream_recycling.c' || echo '$(srcdir)/'`ags/audio/recall/ags_rt_stream_recycling.c
+
 ags/audio/recall/libags_audio_la-ags_stream_audio_signal.lo: ags/audio/recall/ags_stream_audio_signal.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_audio_la_CFLAGS) $(CFLAGS) -MT ags/audio/recall/libags_audio_la-ags_stream_audio_signal.lo -MD -MP -MF ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_stream_audio_signal.Tpo -c -o ags/audio/recall/libags_audio_la-ags_stream_audio_signal.lo `test -f 'ags/audio/recall/ags_stream_audio_signal.c' || echo '$(srcdir)/'`ags/audio/recall/ags_stream_audio_signal.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_stream_audio_signal.Tpo ags/audio/recall/$(DEPDIR)/libags_audio_la-ags_stream_audio_signal.Plo
@@ -10141,6 +10305,34 @@ ags/widget/libags_gui_la-ags_led_array.lo: ags/widget/ags_led_array.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_gui_la_CFLAGS) $(CFLAGS) -c -o ags/widget/libags_gui_la-ags_led_array.lo `test -f 'ags/widget/ags_led_array.c' || echo '$(srcdir)/'`ags/widget/ags_led_array.c
 
+ags/widget/libags_gui_la-ags_level.lo: ags/widget/ags_level.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_gui_la_CFLAGS) $(CFLAGS) -MT ags/widget/libags_gui_la-ags_level.lo -MD -MP -MF ags/widget/$(DEPDIR)/libags_gui_la-ags_level.Tpo -c -o ags/widget/libags_gui_la-ags_level.lo `test -f 'ags/widget/ags_level.c' || echo '$(srcdir)/'`ags/widget/ags_level.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/widget/$(DEPDIR)/libags_gui_la-ags_level.Tpo ags/widget/$(DEPDIR)/libags_gui_la-ags_level.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/widget/ags_level.c' object='ags/widget/libags_gui_la-ags_level.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_gui_la_CFLAGS) $(CFLAGS) -c -o ags/widget/libags_gui_la-ags_level.lo `test -f 'ags/widget/ags_level.c' || echo '$(srcdir)/'`ags/widget/ags_level.c
+
+ags/widget/libags_gui_la-ags_level_box.lo: ags/widget/ags_level_box.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_gui_la_CFLAGS) $(CFLAGS) -MT ags/widget/libags_gui_la-ags_level_box.lo -MD -MP -MF ags/widget/$(DEPDIR)/libags_gui_la-ags_level_box.Tpo -c -o ags/widget/libags_gui_la-ags_level_box.lo `test -f 'ags/widget/ags_level_box.c' || echo '$(srcdir)/'`ags/widget/ags_level_box.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/widget/$(DEPDIR)/libags_gui_la-ags_level_box.Tpo ags/widget/$(DEPDIR)/libags_gui_la-ags_level_box.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/widget/ags_level_box.c' object='ags/widget/libags_gui_la-ags_level_box.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_gui_la_CFLAGS) $(CFLAGS) -c -o ags/widget/libags_gui_la-ags_level_box.lo `test -f 'ags/widget/ags_level_box.c' || echo '$(srcdir)/'`ags/widget/ags_level_box.c
+
+ags/widget/libags_gui_la-ags_hlevel_box.lo: ags/widget/ags_hlevel_box.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_gui_la_CFLAGS) $(CFLAGS) -MT ags/widget/libags_gui_la-ags_hlevel_box.lo -MD -MP -MF ags/widget/$(DEPDIR)/libags_gui_la-ags_hlevel_box.Tpo -c -o ags/widget/libags_gui_la-ags_hlevel_box.lo `test -f 'ags/widget/ags_hlevel_box.c' || echo '$(srcdir)/'`ags/widget/ags_hlevel_box.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/widget/$(DEPDIR)/libags_gui_la-ags_hlevel_box.Tpo ags/widget/$(DEPDIR)/libags_gui_la-ags_hlevel_box.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/widget/ags_hlevel_box.c' object='ags/widget/libags_gui_la-ags_hlevel_box.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_gui_la_CFLAGS) $(CFLAGS) -c -o ags/widget/libags_gui_la-ags_hlevel_box.lo `test -f 'ags/widget/ags_hlevel_box.c' || echo '$(srcdir)/'`ags/widget/ags_hlevel_box.c
+
+ags/widget/libags_gui_la-ags_vlevel_box.lo: ags/widget/ags_vlevel_box.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_gui_la_CFLAGS) $(CFLAGS) -MT ags/widget/libags_gui_la-ags_vlevel_box.lo -MD -MP -MF ags/widget/$(DEPDIR)/libags_gui_la-ags_vlevel_box.Tpo -c -o ags/widget/libags_gui_la-ags_vlevel_box.lo `test -f 'ags/widget/ags_vlevel_box.c' || echo '$(srcdir)/'`ags/widget/ags_vlevel_box.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/widget/$(DEPDIR)/libags_gui_la-ags_vlevel_box.Tpo ags/widget/$(DEPDIR)/libags_gui_la-ags_vlevel_box.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/widget/ags_vlevel_box.c' object='ags/widget/libags_gui_la-ags_vlevel_box.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_gui_la_CFLAGS) $(CFLAGS) -c -o ags/widget/libags_gui_la-ags_vlevel_box.lo `test -f 'ags/widget/ags_vlevel_box.c' || echo '$(srcdir)/'`ags/widget/ags_vlevel_box.c
+
 ags/widget/libags_gui_la-ags_notebook.lo: ags/widget/ags_notebook.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_gui_la_CFLAGS) $(CFLAGS) -MT ags/widget/libags_gui_la-ags_notebook.lo -MD -MP -MF ags/widget/$(DEPDIR)/libags_gui_la-ags_notebook.Tpo -c -o ags/widget/libags_gui_la-ags_notebook.lo `test -f 'ags/widget/ags_notebook.c' || echo '$(srcdir)/'`ags/widget/ags_notebook.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/widget/$(DEPDIR)/libags_gui_la-ags_notebook.Tpo ags/widget/$(DEPDIR)/libags_gui_la-ags_notebook.Plo
@@ -10197,6 +10389,13 @@ ags/widget/libags_gui_la-ags_scrolled_scale_box.lo: ags/widget/ags_scrolled_scal
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_gui_la_CFLAGS) $(CFLAGS) -c -o ags/widget/libags_gui_la-ags_scrolled_scale_box.lo `test -f 'ags/widget/ags_scrolled_scale_box.c' || echo '$(srcdir)/'`ags/widget/ags_scrolled_scale_box.c
 
+ags/widget/libags_gui_la-ags_scrolled_level_box.lo: ags/widget/ags_scrolled_level_box.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_gui_la_CFLAGS) $(CFLAGS) -MT ags/widget/libags_gui_la-ags_scrolled_level_box.lo -MD -MP -MF ags/widget/$(DEPDIR)/libags_gui_la-ags_scrolled_level_box.Tpo -c -o ags/widget/libags_gui_la-ags_scrolled_level_box.lo `test -f 'ags/widget/ags_scrolled_level_box.c' || echo '$(srcdir)/'`ags/widget/ags_scrolled_level_box.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/widget/$(DEPDIR)/libags_gui_la-ags_scrolled_level_box.Tpo ags/widget/$(DEPDIR)/libags_gui_la-ags_scrolled_level_box.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/widget/ags_scrolled_level_box.c' object='ags/widget/libags_gui_la-ags_scrolled_level_box.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_gui_la_CFLAGS) $(CFLAGS) -c -o ags/widget/libags_gui_la-ags_scrolled_level_box.lo `test -f 'ags/widget/ags_scrolled_level_box.c' || echo '$(srcdir)/'`ags/widget/ags_scrolled_level_box.c
+
 ags/widget/libags_gui_la-ags_ruler.lo: ags/widget/ags_ruler.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libags_gui_la_CFLAGS) $(CFLAGS) -MT ags/widget/libags_gui_la-ags_ruler.lo -MD -MP -MF ags/widget/$(DEPDIR)/libags_gui_la-ags_ruler.Tpo -c -o ags/widget/libags_gui_la-ags_ruler.lo `test -f 'ags/widget/ags_ruler.c' || echo '$(srcdir)/'`ags/widget/ags_ruler.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/widget/$(DEPDIR)/libags_gui_la-ags_ruler.Tpo ags/widget/$(DEPDIR)/libags_gui_la-ags_ruler.Plo
@@ -12059,20 +12258,6 @@ ags/X/editor/libgsequencer_la-ags_inline_player_callbacks.lo: ags/X/editor/ags_i
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -c -o ags/X/editor/libgsequencer_la-ags_inline_player_callbacks.lo `test -f 'ags/X/editor/ags_inline_player_callbacks.c' || echo '$(srcdir)/'`ags/X/editor/ags_inline_player_callbacks.c
 
-ags/X/editor/libgsequencer_la-ags_level.lo: ags/X/editor/ags_level.c
- at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -MT ags/X/editor/libgsequencer_la-ags_level.lo -MD -MP -MF ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_level.Tpo -c -o ags/X/editor/libgsequencer_la-ags_level.lo `test -f 'ags/X/editor/ags_level.c' || echo '$(srcdir)/'`ags/X/editor/ags_level.c
- at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_level.Tpo ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_level.Plo
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/X/editor/ags_level.c' object='ags/X/editor/libgsequencer_la-ags_level.lo' libtool=yes @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -c -o ags/X/editor/libgsequencer_la-ags_level.lo `test -f 'ags/X/editor/ags_level.c' || echo '$(srcdir)/'`ags/X/editor/ags_level.c
-
-ags/X/editor/libgsequencer_la-ags_level_callbacks.lo: ags/X/editor/ags_level_callbacks.c
- at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -MT ags/X/editor/libgsequencer_la-ags_level_callbacks.lo -MD -MP -MF ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_level_callbacks.Tpo -c -o ags/X/editor/libgsequencer_la-ags_level_callbacks.lo `test -f 'ags/X/editor/ags_level_callbacks.c' || echo '$(srcdir)/'`ags/X/editor/ags_level_callbacks.c
- at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_level_callbacks.Tpo ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_level_callbacks.Plo
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/X/editor/ags_level_callbacks.c' object='ags/X/editor/libgsequencer_la-ags_level_callbacks.lo' libtool=yes @AMDEPBACKSLASH@
- at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
- at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -c -o ags/X/editor/libgsequencer_la-ags_level_callbacks.lo `test -f 'ags/X/editor/ags_level_callbacks.c' || echo '$(srcdir)/'`ags/X/editor/ags_level_callbacks.c
-
 ags/X/editor/libgsequencer_la-ags_machine_radio_button.lo: ags/X/editor/ags_machine_radio_button.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -MT ags/X/editor/libgsequencer_la-ags_machine_radio_button.lo -MD -MP -MF ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_machine_radio_button.Tpo -c -o ags/X/editor/libgsequencer_la-ags_machine_radio_button.lo `test -f 'ags/X/editor/ags_machine_radio_button.c' || echo '$(srcdir)/'`ags/X/editor/ags_machine_radio_button.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_machine_radio_button.Tpo ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_machine_radio_button.Plo
@@ -12213,6 +12398,13 @@ ags/X/editor/libgsequencer_la-ags_scrolled_automation_edit_box.lo: ags/X/editor/
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -c -o ags/X/editor/libgsequencer_la-ags_scrolled_automation_edit_box.lo `test -f 'ags/X/editor/ags_scrolled_automation_edit_box.c' || echo '$(srcdir)/'`ags/X/editor/ags_scrolled_automation_edit_box.c
 
+ags/X/editor/libgsequencer_la-ags_scrolled_wave_edit_box.lo: ags/X/editor/ags_scrolled_wave_edit_box.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -MT ags/X/editor/libgsequencer_la-ags_scrolled_wave_edit_box.lo -MD -MP -MF ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_scrolled_wave_edit_box.Tpo -c -o ags/X/editor/libgsequencer_la-ags_scrolled_wave_edit_box.lo `test -f 'ags/X/editor/ags_scrolled_wave_edit_box.c' || echo '$(srcdir)/'`ags/X/editor/ags_scrolled_wave_edit_box.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_scrolled_wave_edit_box.Tpo ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_scrolled_wave_edit_box.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/X/editor/ags_scrolled_wave_edit_box.c' object='ags/X/editor/libgsequencer_la-ags_scrolled_wave_edit_box.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -c -o ags/X/editor/libgsequencer_la-ags_scrolled_wave_edit_box.lo `test -f 'ags/X/editor/ags_scrolled_wave_edit_box.c' || echo '$(srcdir)/'`ags/X/editor/ags_scrolled_wave_edit_box.c
+
 ags/X/editor/libgsequencer_la-ags_select_acceleration_dialog.lo: ags/X/editor/ags_select_acceleration_dialog.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -MT ags/X/editor/libgsequencer_la-ags_select_acceleration_dialog.lo -MD -MP -MF ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_select_acceleration_dialog.Tpo -c -o ags/X/editor/libgsequencer_la-ags_select_acceleration_dialog.lo `test -f 'ags/X/editor/ags_select_acceleration_dialog.c' || echo '$(srcdir)/'`ags/X/editor/ags_select_acceleration_dialog.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_select_acceleration_dialog.Tpo ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_select_acceleration_dialog.Plo
@@ -12262,6 +12454,13 @@ ags/X/editor/libgsequencer_la-ags_vautomation_edit_box.lo: ags/X/editor/ags_vaut
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -c -o ags/X/editor/libgsequencer_la-ags_vautomation_edit_box.lo `test -f 'ags/X/editor/ags_vautomation_edit_box.c' || echo '$(srcdir)/'`ags/X/editor/ags_vautomation_edit_box.c
 
+ags/X/editor/libgsequencer_la-ags_vwave_edit_box.lo: ags/X/editor/ags_vwave_edit_box.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -MT ags/X/editor/libgsequencer_la-ags_vwave_edit_box.lo -MD -MP -MF ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_vwave_edit_box.Tpo -c -o ags/X/editor/libgsequencer_la-ags_vwave_edit_box.lo `test -f 'ags/X/editor/ags_vwave_edit_box.c' || echo '$(srcdir)/'`ags/X/editor/ags_vwave_edit_box.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_vwave_edit_box.Tpo ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_vwave_edit_box.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/X/editor/ags_vwave_edit_box.c' object='ags/X/editor/libgsequencer_la-ags_vwave_edit_box.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -c -o ags/X/editor/libgsequencer_la-ags_vwave_edit_box.lo `test -f 'ags/X/editor/ags_vwave_edit_box.c' || echo '$(srcdir)/'`ags/X/editor/ags_vwave_edit_box.c
+
 ags/X/editor/libgsequencer_la-ags_wave_edit.lo: ags/X/editor/ags_wave_edit.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -MT ags/X/editor/libgsequencer_la-ags_wave_edit.lo -MD -MP -MF ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_wave_edit.Tpo -c -o ags/X/editor/libgsequencer_la-ags_wave_edit.lo `test -f 'ags/X/editor/ags_wave_edit.c' || echo '$(srcdir)/'`ags/X/editor/ags_wave_edit.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_wave_edit.Tpo ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_wave_edit.Plo
@@ -12269,6 +12468,13 @@ ags/X/editor/libgsequencer_la-ags_wave_edit.lo: ags/X/editor/ags_wave_edit.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -c -o ags/X/editor/libgsequencer_la-ags_wave_edit.lo `test -f 'ags/X/editor/ags_wave_edit.c' || echo '$(srcdir)/'`ags/X/editor/ags_wave_edit.c
 
+ags/X/editor/libgsequencer_la-ags_wave_edit_box.lo: ags/X/editor/ags_wave_edit_box.c
+ at am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -MT ags/X/editor/libgsequencer_la-ags_wave_edit_box.lo -MD -MP -MF ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_wave_edit_box.Tpo -c -o ags/X/editor/libgsequencer_la-ags_wave_edit_box.lo `test -f 'ags/X/editor/ags_wave_edit_box.c' || echo '$(srcdir)/'`ags/X/editor/ags_wave_edit_box.c
+ at am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_wave_edit_box.Tpo ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_wave_edit_box.Plo
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	$(AM_V_CC)source='ags/X/editor/ags_wave_edit_box.c' object='ags/X/editor/libgsequencer_la-ags_wave_edit_box.lo' libtool=yes @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCC_FALSE@	$(AM_V_CC at am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -c -o ags/X/editor/libgsequencer_la-ags_wave_edit_box.lo `test -f 'ags/X/editor/ags_wave_edit_box.c' || echo '$(srcdir)/'`ags/X/editor/ags_wave_edit_box.c
+
 ags/X/editor/libgsequencer_la-ags_wave_edit_callbacks.lo: ags/X/editor/ags_wave_edit_callbacks.c
 @am__fastdepCC_TRUE@	$(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgsequencer_la_CFLAGS) $(CFLAGS) -MT ags/X/editor/libgsequencer_la-ags_wave_edit_callbacks.lo -MD -MP -MF ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_wave_edit_callbacks.Tpo -c -o ags/X/editor/libgsequencer_la-ags_wave_edit_callbacks.lo `test -f 'ags/X/editor/ags_wave_edit_callbacks.c' || echo '$(srcdir)/'`ags/X/editor/ags_wave_edit_callbacks.c
 @am__fastdepCC_TRUE@	$(AM_V_at)$(am__mv) ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_wave_edit_callbacks.Tpo ags/X/editor/$(DEPDIR)/libgsequencer_la-ags_wave_edit_callbacks.Plo
diff --git a/TODO b/TODO
index 2556d81..bc184cb 100644
--- a/TODO
+++ b/TODO
@@ -1,8 +1,13 @@
 * TODO:JK: implemented AgsWaveWindow, AgsWaveEditor, AgsWaveToolbar and AgsWaveEdit
-* TODO:JK: implemented AgsSelectAudioData and AgsPositionWaveCursor
-* TODO:JK: implemented AgsLevel
-* TODO:JK: implemented ags-capture recall
+* TODO:JK: implemented AgsSelectBuffer and AgsPositionAudioSignalCursor
+* TODO:JK: implemented AgsWave and AgsBuffer
+* TODO:JK: implemented ags-play-wave recall
+* TODO:JK: implemented ags-capture-sound recall
 * TODO:JK: implemented AgsAudiorec
+* TODO:JK: implemented AgsInputCollectionEditor, AgsInputListingEditor and AgsInputEditor
+* TODO:JK: improved ags-feed recall thread-safety
+* TODO:JK: improved ags_audio_signal_feed() reduce over-head
+* TODO:JK: improved AgsApplySynth thread-safety
 * TODO:JK: implemented AgsFunction
 * TODO:JK: implemented AgsServer, AgsRegistry and AgsServerStatus
 * TODO:JK: implemented AgsXmlAuthentication, AgsXmlCertificate and AgsXmlPasswordStore
diff --git a/ags/X/ags_automation_editor.c b/ags/X/ags_automation_editor.c
index 7f2e79c..f5a9419 100644
--- a/ags/X/ags_automation_editor.c
+++ b/ags/X/ags_automation_editor.c
@@ -184,6 +184,7 @@ ags_automation_editor_class_init(AgsAutomationEditorClass *automation_editor)
 void
 ags_automation_editor_init(AgsAutomationEditor *automation_editor)
 {
+  GtkViewport *viewport;
   GtkScrolledWindow *scrolled_window;
   GtkTable *table;
 
@@ -217,11 +218,18 @@ ags_automation_editor_init(AgsAutomationEditor *automation_editor)
 		     0);
 
   /* machine selector */
-  scrolled_window = (GtkScrolledWindow *) gtk_scrolled_window_new(NULL, NULL);
+  viewport = gtk_viewport_new(NULL,
+			      NULL);
+  g_object_set(viewport,
+	       "shadow-type", GTK_SHADOW_NONE,
+	       NULL);
   gtk_paned_pack1((GtkPaned *) automation_editor->paned,
-		  (GtkWidget *) scrolled_window,
+		  (GtkWidget *) viewport,
 		  FALSE, TRUE);
 
+  scrolled_window = (GtkScrolledWindow *) gtk_scrolled_window_new(NULL, NULL);
+  gtk_container_add(viewport,
+		    scrolled_window);
   automation_editor->machine_selector = g_object_new(AGS_TYPE_MACHINE_SELECTOR,
 						     "homogeneous", FALSE,
 						     "spacing", 0,
@@ -242,10 +250,18 @@ ags_automation_editor_init(AgsAutomationEditor *automation_editor)
   automation_editor->selected_machine = NULL;
 
   /* notebook audio, output, input */
-  automation_editor->notebook = (GtkNotebook *) gtk_notebook_new();
+  viewport = gtk_viewport_new(NULL,
+			      NULL);
+  g_object_set(viewport,
+	       "shadow-type", GTK_SHADOW_NONE,
+	       NULL);
   gtk_paned_pack2((GtkPaned *) automation_editor->paned,
-		  (GtkWidget *) automation_editor->notebook,
-		  TRUE, FALSE);
+		  (GtkWidget *) viewport,
+		  TRUE, TRUE);
+
+  automation_editor->notebook = (GtkNotebook *) gtk_notebook_new();
+  gtk_container_add(viewport,
+		    automation_editor->notebook);
   
   /* audio */
   table = (GtkTable *) gtk_table_new(4, 3,
@@ -1699,16 +1715,158 @@ ags_automation_editor_paste(AgsAutomationEditor *automation_editor)
   gint first_x, last_x;
   gboolean paste_from_position;
 
+  auto gint ags_automation_editor_paste_automation_all(xmlNode *automation_node,
+						       AgsTimestamp *timestamp,
+						       gboolean match_line, gboolean no_duplicates);
   auto gint ags_automation_editor_paste_automation(xmlNode *audio_node);
+
+  gint ags_automation_editor_paste_automation_all(xmlNode *automation_node,
+						  AgsTimestamp *timestamp,
+						  gboolean match_line, gboolean no_duplicates)
+  {    
+    AgsAutomation *automation;
+		
+    GList *list_automation;
+    
+    guint first_x;
+    guint current_x;
+    gint i;
+
+    first_x = -1;
+
+    /*  */
+    i = 0;
+		
+    while(notebook == NULL ||
+	  (i = ags_notebook_next_active_tab(notebook,
+					    i)) != -1){		  
+      list_automation = ags_automation_find_near_timestamp_extended(machine->audio->automation, i,
+								    automation_editor->focused_automation_edit->channel_type, automation_editor->focused_automation_edit->control_name,
+								    timestamp);
+
+      if(list_automation == NULL){
+	automation = ags_automation_new(machine->audio,
+					i,
+					automation_editor->focused_automation_edit->channel_type,
+					automation_editor->focused_automation_edit->control_name);
+	automation->timestamp->timer.ags_offset.offset = timestamp->timer.ags_offset.offset;
+	machine->audio->automation = ags_automation_add(machine->audio->automation,
+							automation);
+      }else{
+	automation = AGS_AUTOMATION(list_automation->data);
+      }
+		  
+      if(paste_from_position){
+	xmlNode *child;
+
+	guint x_boundary;
+	  
+	ags_automation_insert_from_clipboard_extended(automation,
+						      automation_node,
+						      TRUE, position_x,
+						      TRUE, position_y,
+						      match_line, no_duplicates);
+
+	/* get boundaries */
+	child = automation_node->children;
+	current_x = 0;
+	  
+	while(child != NULL){
+	  if(child->type == XML_ELEMENT_NODE){
+	    if(!xmlStrncmp(child->name,
+			   "note",
+			   5)){
+	      guint tmp;
+
+	      tmp = g_ascii_strtoull(xmlGetProp(child,
+						"x"),
+				     NULL,
+				     10);
+
+	      if(tmp > current_x){
+		current_x = tmp;
+	      }
+	    }
+	  }
+
+	  child = child->next;
+	}
+
+	x_boundary = g_ascii_strtoull(xmlGetProp(automation_node,
+						 "x_boundary"),
+				      NULL,
+				      10);
+
+
+	if(first_x == -1 || x_boundary < first_x){
+	  first_x = x_boundary;
+	}
+	  
+	if(position_x > x_boundary){
+	  current_x += (position_x - x_boundary);
+	}else{
+	  current_x -= (x_boundary - position_x);
+	}
+	  
+	if(current_x > last_x){
+	  last_x = current_x;
+	}	
+      }else{
+	xmlNode *child;
+
+	ags_automation_insert_from_clipboard(automation,
+					     automation_node,
+					     FALSE, 0,
+					     FALSE, 0);
+
+	/* get boundaries */
+	child = automation_node->children;
+	current_x = 0;
+	  
+	while(child != NULL){
+	  if(child->type == XML_ELEMENT_NODE){
+	    if(!xmlStrncmp(child->name,
+			   "note",
+			   5)){
+	      guint tmp;
+
+	      tmp = g_ascii_strtoull(xmlGetProp(child,
+						"x"),
+				     NULL,
+				     10);
+
+	      if(tmp > current_x){
+		current_x = tmp;
+	      }
+	    }
+	  }
+
+	  child = child->next;
+	}
+
+	if(current_x > last_x){
+	  last_x = current_x;
+	}
+      }
+
+      if(notebook == NULL){
+	break;
+      }
+		  
+      i++;
+    }
+
+    return(first_x);
+  }
   
   gint ags_automation_editor_paste_automation(xmlNode *audio_node){
     AgsTimestamp *timestamp;
-    
-    GList *list_automation;
 
     guint first_x;
     gboolean match_line, no_duplicates;
 
+    first_x = -1;
+
     match_line = ((AGS_AUTOMATION_EDITOR_PASTE_MATCH_LINE & (automation_editor->flags)) != 0) ? TRUE: FALSE;
     no_duplicates = ((AGS_AUTOMATION_EDITOR_PASTE_NO_DUPLICATES & (automation_editor->flags)) != 0) ? TRUE: FALSE;
     
@@ -1734,12 +1892,8 @@ ags_automation_editor_paste(AgsAutomationEditor *automation_editor)
 	      if(!xmlStrncmp(automation_node->name,
 			     "automation",
 			     9)){
-		AgsAutomation *automation;
+		guint64 offset;
 		
-		guint offset;
-		guint current_x;
-		gint i;
-
 		timestamp_node = automation_node->children;
 		offset = 0;
 	  
@@ -1760,130 +1914,20 @@ ags_automation_editor_paste(AgsAutomationEditor *automation_editor)
 		  timestamp_node = timestamp_node->next;
 		}     
 		
+		/* 1st attempt */
+		timestamp->timer.ags_offset.offset = offset;
 		
-		/*  */
-		i = 0;
-		
-		while(notebook == NULL ||
-		      (i = ags_notebook_next_active_tab(notebook,
-							i)) != -1){
-		  timestamp->timer.ags_offset.offset = offset;
-		  
-		  list_automation = ags_automation_find_near_timestamp_extended(machine->audio->automation, i,
-										automation_editor->focused_automation_edit->channel_type, automation_editor->focused_automation_edit->control_name,
-										timestamp);
-
-		  if(list_automation == NULL){
-		    automation = ags_automation_new(machine->audio,
-						    i,
-						    automation_editor->focused_automation_edit->channel_type,
-						    automation_editor->focused_automation_edit->control_name);
-		    AGS_TIMESTAMP(automation->timestamp)->timer.ags_offset.offset = offset;
-		    machine->audio->automation = ags_automation_add(machine->audio->automation,
-								    automation);
-		  }else{
-		    automation = AGS_AUTOMATION(list_automation->data);
-		  }
-		  
-		  if(paste_from_position){
-		    xmlNode *child;
+		first_x = ags_automation_editor_paste_automation_all(automation_node,
+								     timestamp,
+								     match_line, no_duplicates);
 
-		    guint x_boundary;
-	  
-		    ags_automation_insert_from_clipboard_extended(automation,
-								  automation_node,
-								  TRUE, position_x,
-								  TRUE, position_y,
-								  match_line, no_duplicates);
-
-		    /* get boundaries */
-		    child = automation_node->children;
-		    current_x = 0;
-	  
-		    while(child != NULL){
-		      if(child->type == XML_ELEMENT_NODE){
-			if(!xmlStrncmp(child->name,
-				       "note",
-				       5)){
-			  guint tmp;
-
-			  tmp = g_ascii_strtoull(xmlGetProp(child,
-							    "x"),
-						 NULL,
-						 10);
-
-			  if(tmp > current_x){
-			    current_x = tmp;
-			  }
-			}
-		      }
-
-		      child = child->next;
-		    }
+		/* 2nd attempt */
+		timestamp->timer.ags_offset.offset = offset + AGS_AUTOMATION_DEFAULT_OFFSET;
 
-		    x_boundary = g_ascii_strtoull(xmlGetProp(automation_node,
-							     "x_boundary"),
-						  NULL,
-						  10);
-
-
-		    if(first_x == -1 || x_boundary < first_x){
-		      first_x = x_boundary;
-		    }
-	  
-		    if(position_x > x_boundary){
-		      current_x += (position_x - x_boundary);
-		    }else{
-		      current_x -= (x_boundary - position_x);
-		    }
-	  
-		    if(current_x > last_x){
-		      last_x = current_x;
-		    }	
-		  }else{
-		    xmlNode *child;
-
-		    ags_automation_insert_from_clipboard(automation,
-						       automation_node,
-						       FALSE, 0,
-						       FALSE, 0);
-
-		    /* get boundaries */
-		    child = automation_node->children;
-		    current_x = 0;
-	  
-		    while(child != NULL){
-		      if(child->type == XML_ELEMENT_NODE){
-			if(!xmlStrncmp(child->name,
-				       "note",
-				       5)){
-			  guint tmp;
-
-			  tmp = g_ascii_strtoull(xmlGetProp(child,
-							    "x"),
-						 NULL,
-						 10);
-
-			  if(tmp > current_x){
-			    current_x = tmp;
-			  }
-			}
-		      }
-
-		      child = child->next;
-		    }
-
-		    if(current_x > last_x){
-		      last_x = current_x;
-		    }
-		  }
-
-		  if(notebook == NULL){
-		    break;
-		  }
-		  
-		  i++;
-		}
+		ags_automation_editor_paste_automation_all(automation_node,
+							   timestamp,
+							   match_line, no_duplicates);
+		
 	      }
 	    }
 
diff --git a/ags/X/ags_connection_editor.h b/ags/X/ags_connection_editor.h
index e5ebefd..5d99abd 100644
--- a/ags/X/ags_connection_editor.h
+++ b/ags/X/ags_connection_editor.h
@@ -35,8 +35,8 @@
 #define AGS_IS_CONNECTION_EDITOR_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_CONNECTION_EDITOR))
 #define AGS_CONNECTION_EDITOR_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS((obj), AGS_TYPE_CONNECTION_EDITOR, AgsConnectionEditorClass))
 
-#define AGS_CONNECTION_EDITOR_DEFAULT_VERSION "0.7.65\0"
-#define AGS_CONNECTION_EDITOR_DEFAULT_BUILD_ID "Sat Sep 10 07:49:08 CEST 2016\0"
+#define AGS_CONNECTION_EDITOR_DEFAULT_VERSION "0.7.65"
+#define AGS_CONNECTION_EDITOR_DEFAULT_BUILD_ID "Sat Sep 10 07:49:08 CEST 2016"
 
 typedef struct _AgsConnectionEditor AgsConnectionEditor;
 typedef struct _AgsConnectionEditorClass AgsConnectionEditorClass;
diff --git a/ags/X/ags_machine.c b/ags/X/ags_machine.c
index 81c08ae..395039b 100644
--- a/ags/X/ags_machine.c
+++ b/ags/X/ags_machine.c
@@ -2018,7 +2018,7 @@ ags_machine_file_chooser_dialog_new(AgsMachine *machine)
   GtkFileChooserDialog *file_chooser;
   GtkCheckButton *check_button;
 
-  file_chooser = (GtkFileChooserDialog *) gtk_file_chooser_dialog_new(g_strdup("open audio files"),
+  file_chooser = (GtkFileChooserDialog *) gtk_file_chooser_dialog_new(i18n("Open audio files"),
 								      (GtkWindow *) gtk_widget_get_toplevel((GtkWidget *) machine),
 								      GTK_FILE_CHOOSER_ACTION_OPEN,
 								      GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
diff --git a/ags/X/ags_menu_action_callbacks.c b/ags/X/ags_menu_action_callbacks.c
index 690c6ba..11dd449 100644
--- a/ags/X/ags_menu_action_callbacks.c
+++ b/ags/X/ags_menu_action_callbacks.c
@@ -19,29 +19,10 @@
 
 #include <ags/X/ags_menu_action_callbacks.h>
 
-#include <ags/object/ags_application_context.h>
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_applicable.h>
-#include <ags/object/ags_soundcard.h>
-#include <ags/object/ags_sequencer.h>
+#include <ags/libags.h>
+#include <ags/libags-audio.h>
 
-#include <ags/file/ags_file.h>
-
-#include <ags/thread/ags_mutex_manager.h>
-
-#include <ags/plugin/ags_lv2_manager.h>
-#include <ags/plugin/ags_lv2_plugin.h>
-
-#include <ags/audio/ags_midiin.h>
-#include <ags/audio/ags_input.h>
-#include <ags/audio/ags_output.h>
-
-#include <ags/audio/thread/ags_audio_loop.h>
-
-#include <ags/audio/task/ags_save_file.h>
-#include <ags/audio/task/ags_add_audio.h>
-
-#include <ags/X/ags_xorg_application_context.h>
+#include <ags/X/ags_ui_provider.h>
 #include <ags/X/ags_window.h>
 #include <ags/X/ags_export_window.h>
 
@@ -60,6 +41,7 @@
 #include <ags/X/machine/ags_synth.h>
 #include <ags/X/machine/ags_syncsynth.h>
 #include <ags/X/machine/ags_ffplayer.h>
+#include <ags/X/machine/ags_audiorec.h>
 #include <ags/X/machine/ags_ladspa_bridge.h>
 #include <ags/X/machine/ags_dssi_bridge.h>
 #include <ags/X/machine/ags_lv2_bridge.h>
@@ -78,13 +60,13 @@ void ags_menu_action_open_response_callback(GtkFileChooserDialog *file_chooser,
 void
 ags_menu_action_open_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
   GtkFileChooserDialog *file_chooser;
   gint response;
 
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
 
   file_chooser = (GtkFileChooserDialog *) gtk_file_chooser_dialog_new("open file",
 								      (GtkWindow *) window,
@@ -130,13 +112,13 @@ ags_menu_action_open_response_callback(GtkFileChooserDialog *file_chooser, gint
 void
 ags_menu_action_save_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
   
   GError *error;
 
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
 
   if(g_strcmp0(ags_config_get_value(AGS_APPLICATION_CONTEXT(application_context)->config,
 				    AGS_CONFIG_GENERIC,
@@ -177,14 +159,14 @@ ags_menu_action_save_callback(GtkWidget *menu_item, gpointer data)
 void
 ags_menu_action_save_as_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
   GtkFileChooserDialog *file_chooser;
   
   gint response;
         
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
 
   file_chooser = (GtkFileChooserDialog *) gtk_file_chooser_dialog_new("save file as",
 								      (GtkWindow *) window,
@@ -259,11 +241,11 @@ ags_menu_action_save_as_callback(GtkWidget *menu_item, gpointer data)
 void
 ags_menu_action_export_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
 
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
 
   gtk_widget_show_all((GtkWidget *) window->export_window);
 }
@@ -271,14 +253,14 @@ ags_menu_action_export_callback(GtkWidget *menu_item, gpointer data)
 void
 ags_menu_action_quit_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
   GtkDialog *dialog;
   GtkWidget *cancel_button;
   gint response;
 
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
 
   /* ask the user if he wants save to a file */
   dialog = (GtkDialog *) gtk_message_dialog_new(GTK_WINDOW(window),
@@ -322,7 +304,7 @@ ags_menu_action_add_callback(GtkWidget *menu_item, gpointer data)
 void
 ags_menu_action_add_panel_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
   AgsPanel *panel;
   
@@ -335,7 +317,7 @@ ags_menu_action_add_panel_callback(GtkWidget *menu_item, gpointer data)
   pthread_mutex_t *application_mutex;
     
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
 
   mutex_manager = ags_mutex_manager_get_instance();
   application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
@@ -360,7 +342,8 @@ ags_menu_action_add_panel_callback(GtkWidget *menu_item, gpointer data)
 
   gtk_box_pack_start((GtkBox *) window->machines,
 		     GTK_WIDGET(panel),
-		     FALSE, FALSE, 0);
+		     FALSE, FALSE,
+		     0);
 
   AGS_MACHINE(panel)->audio->audio_channels = 2;
 
@@ -377,7 +360,7 @@ ags_menu_action_add_panel_callback(GtkWidget *menu_item, gpointer data)
 void
 ags_menu_action_add_mixer_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
   AgsMixer *mixer;
 
@@ -390,7 +373,7 @@ ags_menu_action_add_mixer_callback(GtkWidget *menu_item, gpointer data)
   pthread_mutex_t *application_mutex;
     
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
 
   mutex_manager = ags_mutex_manager_get_instance();
   application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
@@ -415,7 +398,8 @@ ags_menu_action_add_mixer_callback(GtkWidget *menu_item, gpointer data)
 
   gtk_box_pack_start((GtkBox *) window->machines,
 		     GTK_WIDGET(mixer),
-		     FALSE, FALSE, 0);
+		     FALSE, FALSE,
+		     0);
 
   ags_connectable_connect(AGS_CONNECTABLE(mixer));
 
@@ -431,7 +415,7 @@ ags_menu_action_add_mixer_callback(GtkWidget *menu_item, gpointer data)
 void
 ags_menu_action_add_drum_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
   AgsDrum *drum;
 
@@ -444,7 +428,7 @@ ags_menu_action_add_drum_callback(GtkWidget *menu_item, gpointer data)
   pthread_mutex_t *application_mutex;
     
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
 
   drum = ags_drum_new(G_OBJECT(window->soundcard));
 
@@ -469,7 +453,8 @@ ags_menu_action_add_drum_callback(GtkWidget *menu_item, gpointer data)
 
   gtk_box_pack_start((GtkBox *) window->machines,
 		     GTK_WIDGET(drum),
-		     FALSE, FALSE, 0);
+		     FALSE, FALSE,
+		     0);
 
   /* connect everything */
   ags_connectable_connect(AGS_CONNECTABLE(drum));
@@ -488,7 +473,7 @@ ags_menu_action_add_drum_callback(GtkWidget *menu_item, gpointer data)
 void
 ags_menu_action_add_matrix_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
   AgsMatrix *matrix;
 
@@ -501,7 +486,7 @@ ags_menu_action_add_matrix_callback(GtkWidget *menu_item, gpointer data)
   pthread_mutex_t *application_mutex;
   
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
   
   matrix = ags_matrix_new(G_OBJECT(window->soundcard));
 
@@ -526,7 +511,8 @@ ags_menu_action_add_matrix_callback(GtkWidget *menu_item, gpointer data)
   
   gtk_box_pack_start((GtkBox *) window->machines,
 		     GTK_WIDGET(matrix),
-		     FALSE, FALSE, 0);
+		     FALSE, FALSE,
+		     0);
   
   /* connect everything */
   ags_connectable_connect(AGS_CONNECTABLE(matrix));
@@ -545,7 +531,7 @@ ags_menu_action_add_matrix_callback(GtkWidget *menu_item, gpointer data)
 void
 ags_menu_action_add_synth_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
   AgsSynth *synth;
 
@@ -558,7 +544,7 @@ ags_menu_action_add_synth_callback(GtkWidget *menu_item, gpointer data)
   pthread_mutex_t *application_mutex;
     
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
 
   synth = ags_synth_new(G_OBJECT(window->soundcard));
 
@@ -583,7 +569,8 @@ ags_menu_action_add_synth_callback(GtkWidget *menu_item, gpointer data)
 
   gtk_box_pack_start((GtkBox *) window->machines,
 		     (GtkWidget *) synth,
-		     FALSE, FALSE, 0);
+		     FALSE, FALSE,
+		     0);
 
   ags_connectable_connect(AGS_CONNECTABLE(synth));
 
@@ -597,7 +584,7 @@ ags_menu_action_add_synth_callback(GtkWidget *menu_item, gpointer data)
 void
 ags_menu_action_add_syncsynth_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
   AgsSyncsynth *syncsynth;
 
@@ -610,7 +597,7 @@ ags_menu_action_add_syncsynth_callback(GtkWidget *menu_item, gpointer data)
   pthread_mutex_t *application_mutex;
   
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
 
   syncsynth = ags_syncsynth_new(G_OBJECT(window->soundcard));
 
@@ -635,7 +622,8 @@ ags_menu_action_add_syncsynth_callback(GtkWidget *menu_item, gpointer data)
 
   gtk_box_pack_start((GtkBox *) window->machines,
 		     (GtkWidget *) syncsynth,
-		     FALSE, FALSE, 0);
+		     FALSE, FALSE,
+		     0);
 
   ags_connectable_connect(AGS_CONNECTABLE(syncsynth));
 
@@ -649,7 +637,7 @@ ags_menu_action_add_syncsynth_callback(GtkWidget *menu_item, gpointer data)
 void
 ags_menu_action_add_ffplayer_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
   AgsFFPlayer *ffplayer;
 
@@ -662,7 +650,7 @@ ags_menu_action_add_ffplayer_callback(GtkWidget *menu_item, gpointer data)
   pthread_mutex_t *application_mutex;
   
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
 
   ffplayer = ags_ffplayer_new(G_OBJECT(window->soundcard));
 
@@ -687,7 +675,8 @@ ags_menu_action_add_ffplayer_callback(GtkWidget *menu_item, gpointer data)
 
   gtk_box_pack_start((GtkBox *) window->machines,
 		     (GtkWidget *) ffplayer,
-		     FALSE, FALSE, 0);
+		     FALSE, FALSE,
+		     0);
 
   ags_connectable_connect(AGS_CONNECTABLE(ffplayer));
 
@@ -700,9 +689,63 @@ ags_menu_action_add_ffplayer_callback(GtkWidget *menu_item, gpointer data)
 }
 
 void
+ags_menu_action_add_audiorec_callback(GtkWidget *menu_item, gpointer data)
+{
+  AgsApplicationContext *application_context;
+  AgsWindow *window;
+  AgsAudiorec *audiorec;
+
+  AgsAddAudio *add_audio;
+
+  AgsMutexManager *mutex_manager;
+  AgsThread *main_loop;
+  AgsGuiThread *gui_thread;
+
+  pthread_mutex_t *application_mutex;
+  
+  application_context = ags_application_context_get_instance();
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
+
+  audiorec = ags_audiorec_new(G_OBJECT(window->soundcard));
+
+  mutex_manager = ags_mutex_manager_get_instance();
+  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);    
+
+  /* get audio loop */
+  pthread_mutex_lock(application_mutex);
+
+  main_loop = (AgsThread *) AGS_APPLICATION_CONTEXT(application_context)->main_loop;
+
+  pthread_mutex_unlock(application_mutex);
+
+  /* get task thread */
+  gui_thread = (AgsGuiThread *) ags_thread_find_type(main_loop,
+						     AGS_TYPE_GUI_THREAD);
+
+  add_audio = ags_add_audio_new(window->soundcard,
+				AGS_MACHINE(audiorec)->audio);
+  ags_gui_thread_schedule_task(gui_thread,
+			       add_audio);
+
+  gtk_box_pack_start((GtkBox *) window->machines,
+		     (GtkWidget *) audiorec,
+		     FALSE, FALSE,
+		     0);
+
+  ags_connectable_connect(AGS_CONNECTABLE(audiorec));
+
+  //  audiorec->machine.audio->frequence = ;
+  audiorec->machine.audio->audio_channels = 2;
+  ags_audio_set_pads(AGS_MACHINE(audiorec)->audio, AGS_TYPE_INPUT, 1);
+  ags_audio_set_pads(AGS_MACHINE(audiorec)->audio, AGS_TYPE_OUTPUT, 1);  
+
+  gtk_widget_show_all((GtkWidget *) audiorec);
+}
+
+void
 ags_menu_action_add_ladspa_bridge_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
   AgsLadspaBridge *ladspa_bridge;
 
@@ -722,7 +765,7 @@ ags_menu_action_add_ladspa_bridge_callback(GtkWidget *menu_item, gpointer data)
 			     AGS_MENU_ITEM_EFFECT_KEY);
   
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
   ladspa_bridge = ags_ladspa_bridge_new(G_OBJECT(window->soundcard),
 					filename,
 					effect);
@@ -770,7 +813,7 @@ ags_menu_action_add_ladspa_bridge_callback(GtkWidget *menu_item, gpointer data)
 void
 ags_menu_action_add_dssi_bridge_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
   AgsDssiBridge *dssi_bridge;
 
@@ -790,7 +833,7 @@ ags_menu_action_add_dssi_bridge_callback(GtkWidget *menu_item, gpointer data)
 			     AGS_MENU_ITEM_EFFECT_KEY);
   
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
   dssi_bridge = ags_dssi_bridge_new(G_OBJECT(window->soundcard),
 				    filename,
 				    effect);
@@ -838,7 +881,7 @@ ags_menu_action_add_dssi_bridge_callback(GtkWidget *menu_item, gpointer data)
 void
 ags_menu_action_add_lv2_bridge_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
   AgsLv2Bridge *lv2_bridge;
 
@@ -860,7 +903,7 @@ ags_menu_action_add_lv2_bridge_callback(GtkWidget *menu_item, gpointer data)
 			     AGS_MENU_ITEM_EFFECT_KEY);
   
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
   lv2_bridge = ags_lv2_bridge_new(G_OBJECT(window->soundcard),
 				  filename,
 				  effect);
@@ -944,7 +987,7 @@ ags_menu_action_add_lv2_bridge_callback(GtkWidget *menu_item, gpointer data)
 void
 ags_menu_action_add_live_dssi_bridge_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
   AgsLiveDssiBridge *live_dssi_bridge;
 
@@ -964,7 +1007,7 @@ ags_menu_action_add_live_dssi_bridge_callback(GtkWidget *menu_item, gpointer dat
 			     AGS_MENU_ITEM_EFFECT_KEY);
   
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
   live_dssi_bridge = ags_live_dssi_bridge_new(G_OBJECT(window->soundcard),
 					      filename,
 					      effect);
@@ -1012,7 +1055,7 @@ ags_menu_action_add_live_dssi_bridge_callback(GtkWidget *menu_item, gpointer dat
 void
 ags_menu_action_add_live_lv2_bridge_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
   AgsLiveLv2Bridge *live_lv2_bridge;
 
@@ -1034,7 +1077,7 @@ ags_menu_action_add_live_lv2_bridge_callback(GtkWidget *menu_item, gpointer data
 			     AGS_MENU_ITEM_EFFECT_KEY);
   
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
   live_lv2_bridge = ags_live_lv2_bridge_new(G_OBJECT(window->soundcard),
 					    filename,
 					    effect);
@@ -1092,23 +1135,35 @@ ags_menu_action_add_live_lv2_bridge_callback(GtkWidget *menu_item, gpointer data
 void
 ags_menu_action_automation_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
 
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
 
   gtk_widget_show_all((GtkWidget *) window->automation_window);
 }
 
 void
+ags_menu_action_wave_callback(GtkWidget *menu_item, gpointer data)
+{
+  AgsApplicationContext *application_context;
+  AgsWindow *window;
+
+  application_context = ags_application_context_get_instance();
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
+
+  gtk_widget_show_all((GtkWidget *) window->wave_window);
+}
+
+void
 ags_menu_action_preferences_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
 
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
 
   if(window->preferences != NULL){
     return;
@@ -1126,11 +1181,11 @@ ags_menu_action_preferences_callback(GtkWidget *menu_item, gpointer data)
 void
 ags_menu_action_midi_import_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
 
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
 
   if(window->midi_import_wizard != NULL){
     return;
@@ -1151,11 +1206,11 @@ ags_menu_action_midi_import_callback(GtkWidget *menu_item, gpointer data)
 void
 ags_menu_action_midi_export_track_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
 
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
 
   if(window->midi_export_wizard != NULL){
     return;
@@ -1182,7 +1237,7 @@ ags_menu_action_midi_playback_callback(GtkWidget *menu_item, gpointer data)
 void
 ags_menu_action_about_callback(GtkWidget *menu_item, gpointer data)
 {
-  AgsXorgApplicationContext *application_context;
+  AgsApplicationContext *application_context;
   AgsWindow *window;
 
   static FILE *file = NULL;
@@ -1244,7 +1299,7 @@ ags_menu_action_about_callback(GtkWidget *menu_item, gpointer data)
   }
 
   application_context = ags_application_context_get_instance();
-  window = application_context->window;
+  window = ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context));
 
   gtk_show_about_dialog((GtkWindow *) window,
 			"program-name", "gsequencer",
diff --git a/ags/X/ags_menu_action_callbacks.h b/ags/X/ags_menu_action_callbacks.h
index aa7324e..7aef25f 100644
--- a/ags/X/ags_menu_action_callbacks.h
+++ b/ags/X/ags_menu_action_callbacks.h
@@ -40,6 +40,7 @@ void ags_menu_action_add_matrix_callback(GtkWidget *menu_item, gpointer data);
 void ags_menu_action_add_synth_callback(GtkWidget *menu_item, gpointer data);
 void ags_menu_action_add_syncsynth_callback(GtkWidget *menu_item, gpointer data);
 void ags_menu_action_add_ffplayer_callback(GtkWidget *menu_item, gpointer data);
+void ags_menu_action_add_audiorec_callback(GtkWidget *menu_item, gpointer data);
 
 void ags_menu_action_add_ladspa_bridge_callback(GtkWidget *menu_item, gpointer data);
 void ags_menu_action_add_dssi_bridge_callback(GtkWidget *menu_item, gpointer data);
@@ -49,6 +50,7 @@ void ags_menu_action_add_live_dssi_bridge_callback(GtkWidget *menu_item, gpointe
 void ags_menu_action_add_live_lv2_bridge_callback(GtkWidget *menu_item, gpointer data);
 
 void ags_menu_action_automation_callback(GtkWidget *menu_item, gpointer data);
+void ags_menu_action_wave_callback(GtkWidget *menu_item, gpointer data);
 void ags_menu_action_preferences_callback(GtkWidget *menu_item, gpointer data);
 
 void ags_menu_action_midi_import_callback(GtkWidget *menu_item, gpointer data);
diff --git a/ags/X/ags_menu_bar.c b/ags/X/ags_menu_bar.c
index 53be89b..6def44b 100644
--- a/ags/X/ags_menu_bar.c
+++ b/ags/X/ags_menu_bar.c
@@ -20,12 +20,8 @@
 #include <ags/X/ags_menu_bar.h>
 #include <ags/X/ags_menu_action_callbacks.h>
 
-#include <ags/object/ags_connectable.h>
-
-#include <ags/plugin/ags_base_plugin.h>
-#include <ags/plugin/ags_ladspa_manager.h>
-#include <ags/plugin/ags_dssi_manager.h>
-#include <ags/plugin/ags_lv2_manager.h>
+#include <ags/libags.h>
+#include <ags/libags-audio.h>
 
 #include <dlfcn.h>
 #include <stdio.h>
@@ -194,6 +190,11 @@ ags_menu_bar_init(AgsMenuBar *menu_bar)
   item = (GtkImageMenuItem *) gtk_image_menu_item_new_with_label(i18n("FPlayer"));
   gtk_menu_shell_append((GtkMenuShell*) menu_bar->add, (GtkWidget*) item);
 #endif
+
+#if 0  
+  item = (GtkImageMenuItem *) gtk_image_menu_item_new_with_label(i18n("Audiorec"));
+  gtk_menu_shell_append((GtkMenuShell*) menu_bar->add, (GtkWidget*) item);
+#endif
   
   /* bridge */
   item = (GtkImageMenuItem *) gtk_image_menu_item_new_with_label(i18n("LADSPA"));
@@ -229,6 +230,14 @@ ags_menu_bar_init(AgsMenuBar *menu_bar)
   //			   FALSE);
   gtk_menu_shell_append((GtkMenuShell*) menu_bar->edit, (GtkWidget*) item);
 
+  /* wave */
+#if 0  
+  item = (GtkImageMenuItem *) gtk_image_menu_item_new_with_label(i18n("Wave"));
+  //  gtk_widget_set_sensitive(item,
+  //			   FALSE);
+  gtk_menu_shell_append((GtkMenuShell*) menu_bar->edit, (GtkWidget*) item);
+#endif
+  
   /* preferences */
   gtk_menu_shell_append((GtkMenuShell*) menu_bar->edit,
 			(GtkWidget*) gtk_separator_menu_item_new());
@@ -353,6 +362,12 @@ ags_menu_bar_connect(AgsConnectable *connectable)
   list2 = list2->next;
 #endif
   
+#if 0  
+  g_signal_connect (G_OBJECT (list2->data), "activate",
+                    G_CALLBACK (ags_menu_action_add_audiorec_callback), (gpointer) menu_bar);
+  list2 = list2->next;
+#endif
+  
   /* ladspa */
   list3_start = 
     list3 = gtk_container_get_children((GtkContainer *) gtk_menu_item_get_submenu((GtkMenuItem *) list2->data));
@@ -429,10 +444,17 @@ ags_menu_bar_connect(AgsConnectable *connectable)
   g_list_free(list3_start);
   g_list_free(list2_start);
 
-  /* automation and preferences */
+  /* automation, wave and preferences */
   g_signal_connect (G_OBJECT (list1->data), "activate",
                     G_CALLBACK (ags_menu_action_automation_callback), (gpointer) menu_bar);
   list1 = list1->next;
+
+#if 0  
+  g_signal_connect (G_OBJECT (list1->data), "activate",
+                    G_CALLBACK (ags_menu_action_wave_callback), (gpointer) menu_bar);
+  list1 = list1->next;
+#endif
+  
   list1 = list1->next;
 
   g_signal_connect (G_OBJECT (list1->data), "activate",
diff --git a/ags/X/ags_menu_bar.h b/ags/X/ags_menu_bar.h
index ce7aa30..0e1759a 100644
--- a/ags/X/ags_menu_bar.h
+++ b/ags/X/ags_menu_bar.h
@@ -32,8 +32,8 @@
 #define AGS_IS_MENU_BAR_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_MENU_BAR))
 #define AGS_MENU_BAR_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), AGS_TYPE_MENU_BAR, AgsMenuBarClass))
 
-#define AGS_MENU_ITEM_FILENAME_KEY "ags-menu-bar-filename-key\0"
-#define AGS_MENU_ITEM_EFFECT_KEY "ags-menu-bar-effect-key\0"
+#define AGS_MENU_ITEM_FILENAME_KEY "ags-menu-bar-filename-key"
+#define AGS_MENU_ITEM_EFFECT_KEY "ags-menu-bar-effect-key"
 
 typedef struct _AgsMenuBar AgsMenuBar;
 typedef struct _AgsMenuBarClass AgsMenuBarClass;
diff --git a/ags/X/ags_navigation.c b/ags/X/ags_navigation.c
index c358628..4332039 100644
--- a/ags/X/ags_navigation.c
+++ b/ags/X/ags_navigation.c
@@ -20,16 +20,8 @@
 #include <ags/X/ags_navigation.h>
 #include <ags/X/ags_navigation_callbacks.h>
 
-#include <ags/object/ags_application_context.h>
-#include <ags/object/ags_config.h>
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_soundcard.h>
-
-#include <ags/thread/ags_mutex_manager.h>
-
-#include <ags/audio/thread/ags_audio_loop.h>
-
-#include <ags/audio/task/ags_seek_soundcard.h>
+#include <ags/libags.h> 
+#include <ags/libags-audio.h>
 
 #include <ags/X/ags_window.h>
 #include <ags/X/ags_notation_editor.h>
@@ -745,15 +737,36 @@ ags_navigation_duration_time_queue_draw(GtkWidget *widget)
 {
   AgsNavigation *navigation;
 
+  AgsMutexManager *mutex_manager;
+
   gchar *str;
-  
+
+  pthread_mutex_t *application_mutex;
+  pthread_mutex_t *soundcard_mutex;
+
   navigation = AGS_NAVIGATION(widget);
 
-  if(navigation->soundcard == NULL){
+  mutex_manager = ags_mutex_manager_get_instance();
+  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
+
+  if(!AGS_IS_SOUNDCARD(navigation->soundcard)){
     return(TRUE);
   }
 
+  /* lookup soundcard mutex */
+  pthread_mutex_lock(application_mutex);
+
+  soundcard_mutex = ags_mutex_manager_lookup(mutex_manager,
+					     (GObject *) navigation->soundcard);
+	
+  pthread_mutex_unlock(application_mutex);
+
+  pthread_mutex_lock(soundcard_mutex);
+  
   str = ags_soundcard_get_uptime(AGS_SOUNDCARD(navigation->soundcard));
+
+  pthread_mutex_unlock(soundcard_mutex);
+
   g_object_set(navigation->duration_time,
 	       "label", str,
 	       NULL);
diff --git a/ags/X/ags_navigation_callbacks.c b/ags/X/ags_navigation_callbacks.c
index f17e198..82a145b 100644
--- a/ags/X/ags_navigation_callbacks.c
+++ b/ags/X/ags_navigation_callbacks.c
@@ -19,17 +19,10 @@
 
 #include <ags/X/ags_navigation_callbacks.h>
 
-#include <ags/object/ags_application_context.h>
-#include <ags/object/ags_soundcard.h>
-
-#include <ags/thread/ags_mutex_manager.h>
-
-#include <ags/audio/recall/ags_count_beats_audio.h>
-
-#include <ags/audio/thread/ags_audio_loop.h>
-
-#include <ags/audio/task/recall/ags_apply_bpm.h>
+#include <ags/libags.h>
+#include <ags/libags-audio.h>
 
+#include <ags/X/ags_ui_provider.h>
 #include <ags/X/ags_window.h>
 
 #include <ags/X/thread/ags_gui_thread.h>
@@ -104,17 +97,14 @@ ags_navigation_bpm_callback(GtkWidget *widget,
   /* get audio loop */
   pthread_mutex_lock(application_mutex);
 
-  main_loop = (AgsThread *) application_context->main_loop;
+  gui_thread = (AgsThread *) ags_ui_provider_get_gui_thread(AGS_UI_PROVIDER(application_context));
 
   pthread_mutex_unlock(application_mutex);
 
   /* get task thread */
-  gui_thread = (AgsGuiThread *) ags_thread_find_type(main_loop,
-						       AGS_TYPE_GUI_THREAD);
-
-  apply_bpm = ags_apply_bpm_new(G_OBJECT(window->soundcard),
+  apply_bpm = ags_apply_bpm_new(window->soundcard,
 				navigation->bpm->adjustment->value);
-
+  
   ags_gui_thread_schedule_task(gui_thread,
 			       apply_bpm);
 }
diff --git a/ags/X/ags_notation_editor.c b/ags/X/ags_notation_editor.c
index b9486de..ffb391f 100644
--- a/ags/X/ags_notation_editor.c
+++ b/ags/X/ags_notation_editor.c
@@ -190,6 +190,7 @@ ags_notation_editor_class_init(AgsNotationEditorClass *notation_editor)
 void
 ags_notation_editor_init(AgsNotationEditor *notation_editor)
 {
+  GtkViewport *viewport;
   GtkScrolledWindow *scrolled_window;
   GtkTable *table;
   
@@ -220,11 +221,19 @@ ags_notation_editor_init(AgsNotationEditor *notation_editor)
 		     TRUE, TRUE, 0);
 
   /* machine selector */
-  scrolled_window = (GtkScrolledWindow *) gtk_scrolled_window_new(NULL, NULL);
+  viewport = gtk_viewport_new(NULL,
+			      NULL);
+  g_object_set(viewport,
+	       "shadow-type", GTK_SHADOW_NONE,
+	       NULL);
   gtk_paned_pack1((GtkPaned *) notation_editor->paned,
-		  (GtkWidget *) scrolled_window,
+		  (GtkWidget *) viewport,
 		  FALSE, TRUE);
 
+  scrolled_window = (GtkScrolledWindow *) gtk_scrolled_window_new(NULL, NULL);
+  gtk_container_add(viewport,
+		    scrolled_window);
+
   notation_editor->machine_selector = g_object_new(AGS_TYPE_MACHINE_SELECTOR,
 						   "homogeneous", FALSE,
 						   "spacing", 0,
@@ -247,11 +256,19 @@ ags_notation_editor_init(AgsNotationEditor *notation_editor)
   notation_editor->selected_machine = NULL;
 
   /* table */
+  viewport = gtk_viewport_new(NULL,
+			      NULL);
+  g_object_set(viewport,
+	       "shadow-type", GTK_SHADOW_NONE,
+	       NULL);
+  gtk_paned_pack2((GtkPaned *) notation_editor->paned,
+		  (GtkWidget *) viewport,
+		  TRUE, TRUE);
+
   table = (GtkTable *) gtk_table_new(3, 2,
 				     FALSE);
-  gtk_paned_pack2((GtkPaned *) notation_editor->paned,
-		  (GtkWidget *) table,
-		  TRUE, FALSE);
+  gtk_container_add(viewport,
+		    table);
   
   /* notebook */
   notation_editor->notebook = g_object_new(AGS_TYPE_NOTEBOOK,
@@ -607,7 +624,7 @@ ags_notation_editor_add_note(AgsNotationEditor *notation_editor,
     timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
     timestamp->flags |= AGS_TIMESTAMP_OFFSET;
     
-    timestamp->timer.ags_offset.offset = AGS_NOTATION_DEFAULT_OFFSET * floor(note->x[0] / AGS_NOTATION_DEFAULT_OFFSET);
+    timestamp->timer.ags_offset.offset = (guint64) AGS_NOTATION_DEFAULT_OFFSET * floor((double) note->x[0] / (double) AGS_NOTATION_DEFAULT_OFFSET);
 
     pthread_mutex_lock(audio_mutex);
 
@@ -1146,19 +1163,154 @@ ags_notation_editor_paste(AgsNotationEditor *notation_editor)
   gint first_x, last_x;
   gboolean paste_from_position;
 
+  auto gint ags_notation_editor_paste_notation_all(xmlNode *notation_node,
+						   AgsTimestamp *timestamp,
+						   gboolean match_channel, gboolean no_duplicates);
   auto gint ags_notation_editor_paste_notation(xmlNode *audio_node);
+
+  gint ags_notation_editor_paste_notation_all(xmlNode *notation_node,
+					      AgsTimestamp *timestamp,
+					      gboolean match_channel, gboolean no_duplicates)
+  {    
+    AgsNotation *notation;
+		
+    GList *list_notation;
+    
+    gint first_x;
+    guint current_x;
+    gint i;
+
+    first_x = -1;
+    
+    /*  */
+    i = 0;
+		
+    while((i = ags_notebook_next_active_tab(notation_editor->notebook,
+					    i)) != -1){		  
+      list_notation = ags_notation_find_near_timestamp(machine->audio->notation, i,
+						       timestamp);
+
+      if(list_notation == NULL){
+	notation = ags_notation_new(machine->audio,
+				    i);
+	notation->timestamp->timer.ags_offset.offset = timestamp->timer.ags_offset.offset;
+	machine->audio->notation = ags_notation_add(machine->audio->notation,
+						    notation);
+      }else{
+	notation = AGS_NOTATION(list_notation->data);
+      }
+		  
+      if(paste_from_position){
+	xmlNode *child;
+
+	guint x_boundary;
+	  
+	ags_notation_insert_from_clipboard_extended(notation,
+						    notation_node,
+						    TRUE, position_x,
+						    TRUE, position_y,
+						    match_channel, no_duplicates);
+		    
+	/* get boundaries */
+	child = notation_node->children;
+	current_x = 0;
+	  
+	while(child != NULL){
+	  if(child->type == XML_ELEMENT_NODE){
+	    if(!xmlStrncmp(child->name,
+			   "note",
+			   5)){
+	      guint tmp;
+
+	      tmp = g_ascii_strtoull(xmlGetProp(child,
+						"x1"),
+				     NULL,
+				     10);
+
+	      if(tmp > current_x){
+		current_x = tmp;
+	      }
+	    }
+	  }
+
+	  child = child->next;
+	}
+
+	x_boundary = g_ascii_strtoull(xmlGetProp(notation_node,
+						 "x_boundary"),
+				      NULL,
+				      10);
+
+
+	if(first_x == -1 || x_boundary < first_x){
+	  first_x = x_boundary;
+	}
+	  
+	if(position_x > x_boundary){
+	  current_x += (position_x - x_boundary);
+	}else{
+	  current_x -= (x_boundary - position_x);
+	}
+	  
+	if(current_x > last_x){
+	  last_x = current_x;
+	}	
+      }else{
+	xmlNode *child;
+
+	ags_notation_insert_from_clipboard(notation,
+					   notation_node,
+					   FALSE, 0,
+					   FALSE, 0);
+
+	/* get boundaries */
+	child = notation_node->children;
+	current_x = 0;
+	  
+	while(child != NULL){
+	  if(child->type == XML_ELEMENT_NODE){
+	    if(!xmlStrncmp(child->name,
+			   "note",
+			   5)){
+	      guint tmp;
+
+	      tmp = g_ascii_strtoull(xmlGetProp(child,
+						"x1"),
+				     NULL,
+				     10);
+
+	      if(tmp > current_x){
+		current_x = tmp;
+	      }
+	    }
+	  }
+
+	  child = child->next;
+	}
+
+	if(current_x > last_x){
+	  last_x = current_x;
+	}
+      }
+		  
+      i++;
+    }
+
+    return(first_x);
+  }
   
   gint ags_notation_editor_paste_notation(xmlNode *audio_node){
     AgsTimestamp *timestamp;
-    
-    GList *list_notation;
 
-    guint first_x;
+    gint first_x;
     gboolean match_channel, no_duplicates;
 
+    first_x = -1;
+
     match_channel = ((AGS_NOTATION_EDITOR_PASTE_MATCH_AUDIO_CHANNEL & (notation_editor->flags)) != 0) ? TRUE: FALSE;
     no_duplicates = ((AGS_NOTATION_EDITOR_PASTE_NO_DUPLICATES & (notation_editor->flags)) != 0) ? TRUE: FALSE;
 
+    /* timestamp */
     timestamp = ags_timestamp_new();
 
     timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
@@ -1181,12 +1333,8 @@ ags_notation_editor_paste(AgsNotationEditor *notation_editor)
 	      if(!xmlStrncmp(notation_node->name,
 			     "notation",
 			     9)){
-		AgsNotation *notation;
+		guint64 offset;
 		
-		guint offset;
-		guint current_x;
-		gint i;
-
 		timestamp_node = notation_node->children;
 		offset = 0;
 	  
@@ -1206,123 +1354,20 @@ ags_notation_editor_paste(AgsNotationEditor *notation_editor)
 
 		  timestamp_node = timestamp_node->next;
 		}     
-		
-		
-		/*  */
-		i = 0;
-		
-		while((i = ags_notebook_next_active_tab(notation_editor->notebook,
-							i)) != -1){
-		  timestamp->timer.ags_offset.offset = offset;
-		  
-		  list_notation = ags_notation_find_near_timestamp(machine->audio->notation, i,
-								   timestamp);
-
-		  if(list_notation == NULL){
-		    notation = ags_notation_new(machine->audio,
-						i);
-		    AGS_TIMESTAMP(notation->timestamp)->timer.ags_offset.offset = offset;
-		    machine->audio->notation = ags_notation_add(machine->audio->notation,
-								notation);
-		  }else{
-		    notation = AGS_NOTATION(list_notation->data);
-		  }
-		  
-		  if(paste_from_position){
-		    xmlNode *child;
-
-		    guint x_boundary;
-	  
-		    ags_notation_insert_from_clipboard_extended(notation,
-								notation_node,
-								TRUE, position_x,
-								TRUE, position_y,
-								match_channel, no_duplicates);
-		    
-		    /* get boundaries */
-		    child = notation_node->children;
-		    current_x = 0;
-	  
-		    while(child != NULL){
-		      if(child->type == XML_ELEMENT_NODE){
-			if(!xmlStrncmp(child->name,
-				       "note",
-				       5)){
-			  guint tmp;
-
-			  tmp = g_ascii_strtoull(xmlGetProp(child,
-							    "x1"),
-						 NULL,
-						 10);
-
-			  if(tmp > current_x){
-			    current_x = tmp;
-			  }
-			}
-		      }
-
-		      child = child->next;
-		    }
-
-		    x_boundary = g_ascii_strtoull(xmlGetProp(notation_node,
-							     "x_boundary"),
-						  NULL,
-						  10);
 
+		/* 1st attempt */
+		timestamp->timer.ags_offset.offset = offset;
+		
+		first_x = ags_notation_editor_paste_notation_all(notation_node,
+								 timestamp,
+								 match_channel, no_duplicates);
 
-		    if(first_x == -1 || x_boundary < first_x){
-		      first_x = x_boundary;
-		    }
-	  
-		    if(position_x > x_boundary){
-		      current_x += (position_x - x_boundary);
-		    }else{
-		      current_x -= (x_boundary - position_x);
-		    }
-	  
-		    if(current_x > last_x){
-		      last_x = current_x;
-		    }	
-		  }else{
-		    xmlNode *child;
-
-		    ags_notation_insert_from_clipboard(notation,
-						       notation_node,
-						       FALSE, 0,
-						       FALSE, 0);
-
-		    /* get boundaries */
-		    child = notation_node->children;
-		    current_x = 0;
-	  
-		    while(child != NULL){
-		      if(child->type == XML_ELEMENT_NODE){
-			if(!xmlStrncmp(child->name,
-				       "note",
-				       5)){
-			  guint tmp;
-
-			  tmp = g_ascii_strtoull(xmlGetProp(child,
-							    "x1"),
-						 NULL,
-						 10);
-
-			  if(tmp > current_x){
-			    current_x = tmp;
-			  }
-			}
-		      }
-
-		      child = child->next;
-		    }
+		/* 2nd attempt */
+		timestamp->timer.ags_offset.offset = offset + AGS_NOTATION_DEFAULT_OFFSET;
 
-		    if(current_x > last_x){
-		      last_x = current_x;
-		    }
-		  }
-		  
-		  i++;
-		}
+		ags_notation_editor_paste_notation_all(notation_node,
+						       timestamp,
+						       match_channel, no_duplicates);
 	      }
 	    }
 
diff --git a/ags/X/ags_notation_editor_callbacks.c b/ags/X/ags_notation_editor_callbacks.c
index fe87775..ef264eb 100644
--- a/ags/X/ags_notation_editor_callbacks.c
+++ b/ags/X/ags_notation_editor_callbacks.c
@@ -117,16 +117,19 @@ ags_notation_editor_resize_pads_callback(AgsMachine *machine, GType channel_type
 void
 ags_notation_editor_init_channel_launch_callback(AgsTask *task, AgsNote *note)
 {
-  GObject *soundcard;
+  AgsAudio *audio;
   AgsChannel *channel;
-  AgsRecycling *recycling;
-
+  AgsRecycling *recycling, *last_recycling;
+  AgsRecallID *recall_id;
+  
   AgsAddAudioSignal *add_audio_signal;
 
-  AgsThread *main_loop;
+  AgsMutexManager *mutex_manager;
 
   AgsApplicationContext *application_context;
   AgsConfig *config;
+
+  GObject *soundcard;
   
   GList *recall, *tmp;
   GList *delay_audio;
@@ -136,32 +139,74 @@ ags_notation_editor_init_channel_launch_callback(AgsTask *task, AgsNote *note)
   guint samplerate;
   
   GValue value = {0,};
-  
+
+  pthread_mutex_t *application_mutex;
+  pthread_mutex_t *soundcard_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);
+
   channel = AGS_INIT_CHANNEL(task)->channel;
 
+  /* */
+  pthread_mutex_lock(application_mutex);
+
+  channel_mutex = ags_mutex_manager_lookup(mutex_manager,
+					   (GObject *) channel);
+
+  pthread_mutex_unlock(application_mutex);
+
+  /* */
+  pthread_mutex_lock(channel_mutex);
+  
   soundcard = channel->soundcard;
-  application_context = ags_soundcard_get_application_context(AGS_SOUNDCARD(soundcard));
+  audio = channel->audio;
+  
+  pthread_mutex_unlock(channel_mutex);
+
+  /* */
+  pthread_mutex_lock(application_mutex);
+
+  soundcard_mutex = ags_mutex_manager_lookup(mutex_manager,
+					     (GObject *) soundcard);
+
+  pthread_mutex_unlock(application_mutex);
+
+  /*  */
+  pthread_mutex_lock(soundcard_mutex);
+
   ags_soundcard_get_presets(AGS_SOUNDCARD(soundcard),
 			    NULL,
 			    &samplerate,
 			    NULL,
 			    NULL);
-  
-  main_loop = (AgsThread *) application_context->main_loop;
 
+  pthread_mutex_unlock(soundcard_mutex);
+  
 #ifdef AGS_DEBUG
   g_message("launch");
 #endif
-  
+
+  pthread_mutex_lock(channel_mutex);
+
   if(AGS_PLAYBACK(channel->playback) == NULL ||
      AGS_PLAYBACK(channel->playback)->recall_id[0] == NULL){    
+
+    pthread_mutex_unlock(channel_mutex);
+    
     return;
   }
 
+  recall_id = AGS_PLAYBACK(channel->playback)->recall_id[0];
+  last_recycling = channel->last_recycling;
+  
   /* connect done */
   recall = ags_recall_find_provider_with_recycling_context(channel->play,
 							   G_OBJECT(channel),
-							   G_OBJECT(AGS_PLAYBACK(channel->playback)->recall_id[0]->recycling_context));
+							   G_OBJECT(recall_id->recycling_context));
   
   tmp = recall;
   recall = ags_recall_find_type(recall,
@@ -169,8 +214,20 @@ ags_notation_editor_init_channel_launch_callback(AgsTask *task, AgsNote *note)
   //FIXME:JK: below
   //    g_list_free(tmp);
 
+  pthread_mutex_unlock(channel_mutex);
+
+  /* */
+  pthread_mutex_lock(application_mutex);
+
+  audio_mutex = ags_mutex_manager_lookup(mutex_manager,
+					 (GObject *) audio);
+
+  pthread_mutex_unlock(application_mutex);
+
   /* read notation delay */
-  delay_audio = channel->recall;
+  pthread_mutex_lock(audio_mutex);
+
+  delay_audio = audio->play;
   delay_audio = ags_recall_find_type(delay_audio,
 				     AGS_TYPE_DELAY_AUDIO);
   
@@ -184,31 +241,71 @@ ags_notation_editor_init_channel_launch_callback(AgsTask *task, AgsNote *note)
     notation_delay = 1.0;
   }
   
+  pthread_mutex_unlock(audio_mutex);
+
   if(recall != NULL){
     AgsAudioSignal *audio_signal;
       
     /* add audio signal */
     recycling = channel->first_recycling;
 
-    while(recycling != channel->last_recycling->next){
-      audio_signal = ags_audio_signal_new((GObject *) soundcard,
-					  (GObject *) recycling,
-					  (GObject *) AGS_RECALL(recall->data)->recall_id);
-      /* add audio signal */
-      ags_recycling_create_audio_signal_with_frame_count(recycling,
-							 audio_signal,
-							 (note->x[1] - note->x[0]) * ((gdouble) samplerate / notation_delay),
-							 0.0, 0);
-      audio_signal->stream_current = audio_signal->stream_beginning;
-      ags_connectable_connect(AGS_CONNECTABLE(audio_signal));
-  
-      /*
-       * emit add_audio_signal on AgsRecycling
-       */
-      ags_recycling_add_audio_signal(recycling,
-				     audio_signal);
+    while(recycling != last_recycling->next){
+      /* get recycling mutex */
+      pthread_mutex_lock(application_mutex);
+  
+      recycling_mutex = ags_mutex_manager_lookup(mutex_manager,
+						 (GObject *) recycling);
+	
+      pthread_mutex_unlock(application_mutex);
+      
+      if(!AGS_RECALL(recall->data)->rt_safe){
+	audio_signal = ags_audio_signal_new((GObject *) soundcard,
+					    (GObject *) recycling,
+					    (GObject *) recall_id);
+	g_object_set(audio_signal,
+		     "note", note,
+		     NULL);
+	
+	/* add audio signal */
+	ags_recycling_create_audio_signal_with_frame_count(recycling,
+							   audio_signal,
+							   (note->x[1] - note->x[0]) * ((gdouble) samplerate / notation_delay),
+							   0.0, 0);
+	audio_signal->stream_current = audio_signal->stream_beginning;
+	ags_connectable_connect(AGS_CONNECTABLE(audio_signal));
+  
+	/*
+	 * emit add_audio_signal on AgsRecycling
+	 */
+	ags_recycling_add_audio_signal(recycling,
+				       audio_signal);
+      }else{
+	GList *list;
+
+	pthread_mutex_lock(recycling_mutex);
+	    
+	audio_signal = NULL;
+	list = ags_audio_signal_get_by_recall_id(recycling->audio_signal,
+						 recall_id);
+	    
+	if(list != NULL){
+	  audio_signal = list->data;
+
+	  g_object_set(audio_signal,
+		       "note", note,
+		       NULL);
+	}
+
+	note->rt_offset = 0;
 
+	pthread_mutex_unlock(recycling_mutex);
+      }
+      
+      pthread_mutex_lock(recycling_mutex);
+      
       recycling = recycling->next;
+
+      pthread_mutex_unlock(recycling_mutex);
     }    
   }
 }
diff --git a/ags/X/ags_pad.c b/ags/X/ags_pad.c
index 904be5b..86ae0c2 100644
--- a/ags/X/ags_pad.c
+++ b/ags/X/ags_pad.c
@@ -811,7 +811,7 @@ ags_pad_play(AgsPad *pad)
 
   /* get task */
   gui_thread = (AgsGuiThread *) ags_thread_find_type(main_loop,
-						       AGS_TYPE_GUI_THREAD);
+						     AGS_TYPE_GUI_THREAD);
 
   /*  */
   tasks = NULL;
diff --git a/ags/X/ags_pad_callbacks.c b/ags/X/ags_pad_callbacks.c
index 034fdd8..e9a0bcc 100644
--- a/ags/X/ags_pad_callbacks.c
+++ b/ags/X/ags_pad_callbacks.c
@@ -267,6 +267,7 @@ ags_pad_init_channel_launch_callback(AgsTask *task,
   AgsSoundcard *soundcard;
   AgsAudio *audio;
   AgsChannel *channel, *next_pad;
+  AgsRecycling *last_recycling;
   AgsRecycling *recycling, *end_recycling;
 
   AgsAddAudioSignal *add_audio_signal;
@@ -350,17 +351,34 @@ ags_pad_init_channel_launch_callback(AgsTask *task,
     if(recall != NULL){
       AgsAudioSignal *audio_signal;
       AgsRecallID *current_recall_id;
+      AgsNote *note;
       
       /* add audio signal */
       pthread_mutex_lock(channel_mutex);
       
       recycling = channel->first_recycling;
-      end_recycling = channel->last_recycling->next;
+      last_recycling = channel->last_recycling;
 
+      note = AGS_PLAYBACK(channel->playback)->play_note;
+      
       current_recall_id = AGS_RECALL(recall->data)->recall_id;
       
       pthread_mutex_unlock(channel_mutex);
 
+      /* get recycling mutex */
+      pthread_mutex_lock(application_mutex);
+  
+      recycling_mutex = ags_mutex_manager_lookup(mutex_manager,
+						 (GObject *) last_recycling);
+	
+      pthread_mutex_unlock(application_mutex);
+
+      pthread_mutex_lock(recycling_mutex);
+      
+      end_recycling = last_recycling->next;
+
+      pthread_mutex_unlock(recycling_mutex);
+      
       while(recycling != end_recycling){
 	/* get recycling mutex */
 	pthread_mutex_lock(application_mutex);
@@ -370,24 +388,48 @@ ags_pad_init_channel_launch_callback(AgsTask *task,
 	
 	pthread_mutex_unlock(application_mutex);
 
-	/* instantiate audio signal */
-	audio_signal = ags_audio_signal_new((GObject *) soundcard,
-					    (GObject *) recycling,
-					    (GObject *) current_recall_id);
-	
-	/* add audio signal */
-	ags_recycling_create_audio_signal_with_defaults(recycling,
-							audio_signal,
-							0.0, 0);
-	audio_signal->stream_current = audio_signal->stream_beginning;
-	ags_connectable_connect(AGS_CONNECTABLE(audio_signal));
+	if(!AGS_RECALL(recall->data)->rt_safe){
+	  /* instantiate audio signal */
+	  audio_signal = ags_audio_signal_new((GObject *) soundcard,
+					      (GObject *) recycling,
+					      (GObject *) current_recall_id);
+	  g_object_set(audio_signal,
+		       "note", note,
+		       NULL);
+	  
+	  /* add audio signal */
+	  ags_recycling_create_audio_signal_with_defaults(recycling,
+							  audio_signal,
+							  0.0, 0);
+	  audio_signal->stream_current = audio_signal->stream_beginning;
+	  ags_connectable_connect(AGS_CONNECTABLE(audio_signal));
   
-	/*
-	 * emit add_audio_signal on AgsRecycling
-	 */
-	ags_recycling_add_audio_signal(recycling,
-				       audio_signal);
-
+	  /*
+	   * emit add_audio_signal on AgsRecycling
+	   */
+	  ags_recycling_add_audio_signal(recycling,
+					 audio_signal);
+	}else{
+	  GList *list;
+
+	  pthread_mutex_lock(recycling_mutex);
+	    
+	  audio_signal = NULL;
+	  list = ags_audio_signal_get_by_recall_id(recycling->audio_signal,
+						   current_recall_id);
+	    
+	  if(list != NULL){
+	    audio_signal = list->data;
+
+	    g_object_set(audio_signal,
+			 "note", note,
+			 NULL);
+	  }
+
+	  note->rt_offset = 0;
+
+	  pthread_mutex_unlock(recycling_mutex);
+	}
 
 	/* iterate recycling */
 	pthread_mutex_lock(recycling_mutex);
diff --git a/ags/X/ags_ui_provider.c b/ags/X/ags_ui_provider.c
index d836b3d..7e21e3e 100644
--- a/ags/X/ags_ui_provider.c
+++ b/ags/X/ags_ui_provider.c
@@ -97,3 +97,138 @@ ags_ui_provider_set_window(AgsUiProvider *ui_provider,
   ui_provider_interface->set_window(ui_provider,
 				    window);
 }
+
+/**
+ * ags_ui_provider_get_gui_thread:
+ * @ui_provider: the #AgsUiProvider
+ * 
+ * Get gui thread.
+ * 
+ * Returns: the #AgsGuiThread
+ * 
+ * Since: 1.4.0
+ */
+AgsThread*
+ags_ui_provider_get_gui_thread(AgsUiProvider *ui_provider)
+{
+  AgsUiProviderInterface *ui_provider_interface;
+
+  g_return_val_if_fail(AGS_IS_UI_PROVIDER(ui_provider), NULL);
+  ui_provider_interface = AGS_UI_PROVIDER_GET_INTERFACE(ui_provider);
+  g_return_val_if_fail(ui_provider_interface->get_gui_thread, NULL);
+
+  return(ui_provider_interface->get_gui_thread(ui_provider));
+}
+
+/**
+ * ags_ui_provider_get_gui_thread:
+ * @ui_provider: the #AgsUiProvider
+ * @gui_thread: the #AgsGuiThread
+ * 
+ * Set gui thread.
+ * 
+ * Since: 1.4.0
+ */
+void
+ags_ui_provider_set_gui_thread(AgsUiProvider *ui_provider,
+			       AgsThread *gui_thread)
+{
+  AgsUiProviderInterface *ui_provider_interface;
+
+  g_return_if_fail(AGS_IS_UI_PROVIDER(ui_provider));
+  ui_provider_interface = AGS_UI_PROVIDER_GET_INTERFACE(ui_provider);
+  g_return_if_fail(ui_provider_interface->set_gui_thread);
+
+  ui_provider_interface->set_gui_thread(ui_provider,
+					gui_thread);
+}
+
+/**
+ * ags_ui_provider_get_show_animation:
+ * @ui_provider: the #AgsUiProvider
+ * 
+ * Get show animation.
+ * 
+ * Returns: %TRUE if animation does show, else %FALSE
+ * 
+ * Since: 1.4.0
+ */
+gboolean
+ags_ui_provider_get_show_animation(AgsUiProvider *ui_provider)
+{
+  AgsUiProviderInterface *ui_provider_interface;
+
+  g_return_val_if_fail(AGS_IS_UI_PROVIDER(ui_provider), NULL);
+  ui_provider_interface = AGS_UI_PROVIDER_GET_INTERFACE(ui_provider);
+  g_return_val_if_fail(ui_provider_interface->get_show_animation, NULL);
+
+  return(ui_provider_interface->get_show_animation(ui_provider));
+}
+
+/**
+ * ags_ui_provider_set_show_animation:
+ * @ui_provider: the #AgsUiProvider
+ * @do_show_animation: do show animation
+ * 
+ * Set show animation.
+ * 
+ * Since: 1.4.0
+ */
+void
+ags_ui_provider_set_show_animation(AgsUiProvider *ui_provider,
+				   gboolean do_show_animation)
+{
+  AgsUiProviderInterface *ui_provider_interface;
+
+  g_return_if_fail(AGS_IS_UI_PROVIDER(ui_provider));
+  ui_provider_interface = AGS_UI_PROVIDER_GET_INTERFACE(ui_provider);
+  g_return_if_fail(ui_provider_interface->set_show_animation);
+
+  ui_provider_interface->set_show_animation(ui_provider,
+					    do_show_animation);
+}
+
+/**
+ * ags_ui_provider_get_gui_ready:
+ * @ui_provider: the #AgsUiProvider
+ * 
+ * Get GUI ready.
+ * 
+ * Returns: %TRUE if gui is ready, else %FALSE
+ * 
+ * Since: 1.4.0
+ */
+gboolean
+ags_ui_provider_get_gui_ready(AgsUiProvider *ui_provider)
+{
+  AgsUiProviderInterface *ui_provider_interface;
+
+  g_return_val_if_fail(AGS_IS_UI_PROVIDER(ui_provider), NULL);
+  ui_provider_interface = AGS_UI_PROVIDER_GET_INTERFACE(ui_provider);
+  g_return_val_if_fail(ui_provider_interface->get_gui_ready, NULL);
+
+  return(ui_provider_interface->get_gui_ready(ui_provider));
+}
+
+/**
+ * ags_ui_provider_set_gui_ready:
+ * @ui_provider: the #AgsUiProvider
+ * @is_gui_ready: is GUI ready
+ * 
+ * Set GUI ready.
+ * 
+ * Since: 1.4.0
+ */
+void
+ags_ui_provider_set_gui_ready(AgsUiProvider *ui_provider,
+			      gboolean is_gui_ready)
+{
+  AgsUiProviderInterface *ui_provider_interface;
+
+  g_return_if_fail(AGS_IS_UI_PROVIDER(ui_provider));
+  ui_provider_interface = AGS_UI_PROVIDER_GET_INTERFACE(ui_provider);
+  g_return_if_fail(ui_provider_interface->set_gui_ready);
+
+  ui_provider_interface->set_gui_ready(ui_provider,
+				       is_gui_ready);
+}
diff --git a/ags/X/ags_ui_provider.h b/ags/X/ags_ui_provider.h
index 8a7ef28..31b0c6d 100644
--- a/ags/X/ags_ui_provider.h
+++ b/ags/X/ags_ui_provider.h
@@ -25,6 +25,8 @@
 
 #include <gtk/gtk.h>
 
+#include <ags/libags.h>
+
 #define AGS_TYPE_UI_PROVIDER                    (ags_ui_provider_get_type())
 #define AGS_UI_PROVIDER(obj)                    (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_UI_PROVIDER, AgsUiProvider))
 #define AGS_UI_PROVIDER_INTERFACE(vtable)       (G_TYPE_CHECK_CLASS_CAST((vtable), AGS_TYPE_UI_PROVIDER, AgsUiProviderInterface))
@@ -42,6 +44,18 @@ struct _AgsUiProviderInterface
   GtkWidget* (*get_window)(AgsUiProvider *ui_provider);
   void (*set_window)(AgsUiProvider *ui_provider,
 		     GtkWidget *window);
+
+  AgsThread* (*get_gui_thread)(AgsUiProvider *ui_provider);
+  void (*set_gui_thread)(AgsUiProvider *ui_provider,
+			 AgsThread *gui_thread);
+  
+  gboolean (*get_show_animation)(AgsUiProvider *ui_provider);
+  void (*set_show_animation)(AgsUiProvider *ui_provider,
+			     gboolean do_show_animation);
+
+  gboolean (*get_gui_ready)(AgsUiProvider *ui_provider);
+  void (*set_gui_ready)(AgsUiProvider *ui_provider,
+			gboolean is_gui_ready);  
 };
 
 GType ags_ui_provider_get_type();
@@ -50,4 +64,16 @@ GtkWidget* ags_ui_provider_get_window(AgsUiProvider *ui_provider);
 void ags_ui_provider_set_window(AgsUiProvider *ui_provider,
 				GtkWidget *window);
 
+AgsThread* ags_ui_provider_get_gui_thread(AgsUiProvider *ui_provider);
+void ags_ui_provider_set_gui_thread(AgsUiProvider *ui_provider,
+				    AgsThread *gui_thread);
+
+gboolean ags_ui_provider_get_show_animation(AgsUiProvider *ui_provider);
+void ags_ui_provider_set_show_animation(AgsUiProvider *ui_provider,
+					gboolean do_show_animation);
+
+gboolean ags_ui_provider_get_gui_ready(AgsUiProvider *ui_provider);
+void ags_ui_provider_set_gui_ready(AgsUiProvider *ui_provider,
+				   gboolean is_gui_ready);
+
 #endif /*__AGS_UI_PROVIDER_H__*/
diff --git a/ags/X/ags_wave_editor.c b/ags/X/ags_wave_editor.c
index 1e0657b..a11f9d7 100644
--- a/ags/X/ags_wave_editor.c
+++ b/ags/X/ags_wave_editor.c
@@ -26,6 +26,10 @@
 
 #include <ags/X/ags_window.h>
 
+#include <ags/X/editor/ags_scrolled_wave_edit_box.h>
+#include <ags/X/editor/ags_vwave_edit_box.h>
+#include <ags/X/editor/ags_wave_edit.h>
+
 #include <libxml/tree.h>
 #include <libxml/xpath.h>
 
@@ -180,9 +184,12 @@ ags_wave_editor_class_init(AgsWaveEditorClass *wave_editor)
 void
 ags_wave_editor_init(AgsWaveEditor *wave_editor)
 {
-  GtkHPaned *paned;
-  GtkScrolledWindow *scrolled_window;
+  GtkViewport *viewport;
+  GtkScrolledWindow *scrolled_window;  
+  GtkTable *table;
   
+  GtkAdjustment *adjustment;
+
   g_signal_connect_after((GObject *) wave_editor, "parent-set",
 			 G_CALLBACK(ags_wave_editor_parent_set_callback), wave_editor);
 
@@ -191,6 +198,11 @@ ags_wave_editor_init(AgsWaveEditor *wave_editor)
   wave_editor->version = AGS_WAVE_EDITOR_DEFAULT_VERSION;
   wave_editor->build_id = AGS_WAVE_EDITOR_DEFAULT_BUILD_ID;
 
+  /* offset */
+  wave_editor->tact_counter = 0;
+  wave_editor->current_tact = 0.0;
+
+  /* soundcard */
   wave_editor->soundcard = NULL;
 
   wave_editor->wave_toolbar = ags_wave_toolbar_new();
@@ -198,14 +210,24 @@ ags_wave_editor_init(AgsWaveEditor *wave_editor)
 		     (GtkWidget *) wave_editor->wave_toolbar,
 		     FALSE, FALSE, 0);
 
-  paned = (GtkHPaned *) gtk_hpaned_new();
+  wave_editor->paned = (GtkHPaned *) gtk_hpaned_new();
   gtk_box_pack_start((GtkBox *) wave_editor,
-		     (GtkWidget *) paned,
+		     (GtkWidget *) wave_editor->paned,
 		     TRUE, TRUE, 0);
 
+  /* machine selector */
+  viewport = gtk_viewport_new(NULL,
+			      NULL);
+  g_object_set(viewport,
+	       "shadow-type", GTK_SHADOW_NONE,
+	       NULL);
+  gtk_paned_pack1((GtkPaned *) wave_editor->paned,
+		  (GtkWidget *) viewport,
+		  FALSE, TRUE);
+
   scrolled_window = (GtkScrolledWindow *) gtk_scrolled_window_new(NULL, NULL);
-  gtk_paned_pack1((GtkPaned *) paned, (GtkWidget *) scrolled_window, FALSE, TRUE);
-  //  gtk_widget_set_size_request((GtkWidget *) scrolled_window, 180, -1);
+  gtk_container_add(viewport,
+		    scrolled_window);
 
   wave_editor->machine_selector = g_object_new(AGS_TYPE_MACHINE_SELECTOR,
 					       "homogeneous", FALSE,
@@ -221,21 +243,100 @@ ags_wave_editor_init(AgsWaveEditor *wave_editor)
   
   gtk_scrolled_window_add_with_viewport(scrolled_window, (GtkWidget *) wave_editor->machine_selector);
 
+  /* selected machine */
   wave_editor->selected_machine = NULL;
 
-  wave_editor->table = (GtkTable *) gtk_table_new(4, 3, FALSE);
-  gtk_paned_pack2((GtkPaned *) paned,
-		  (GtkWidget *) wave_editor->table,
-		  TRUE, FALSE);
-
-  /* currenty selected widgets */
-  wave_editor->notebook = NULL;  
-  wave_editor->level = NULL;
-  wave_editor->wave_edit = NULL;
-
-  /* offset */
-  wave_editor->tact_counter = 0;
-  wave_editor->current_tact = 0.0;
+  /* table */
+  viewport = gtk_viewport_new(NULL,
+			      NULL);
+  g_object_set(viewport,
+	       "shadow-type", GTK_SHADOW_NONE,
+	       NULL);
+  gtk_paned_pack2((GtkPaned *) wave_editor->paned,
+		  (GtkWidget *) viewport,
+		  TRUE, TRUE);
+
+  table = (GtkTable *) gtk_table_new(4, 3, FALSE);
+  gtk_container_add(viewport,
+		    table);
+
+  /* scrollbars */
+  adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 1.0, AGS_WAVE_EDIT_DEFAULT_CONTROL_HEIGHT, 1.0);
+  wave_editor->vscrollbar = gtk_vscrollbar_new(adjustment);
+  gtk_table_attach(table,
+		   (GtkWidget *) wave_editor->vscrollbar,
+		   2, 3,
+		   2, 3,
+		   GTK_FILL, GTK_FILL,
+		   0, 0);
+
+  adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 1.0, AGS_WAVE_EDIT_DEFAULT_CONTROL_WIDTH, 1.0);
+  wave_editor->hscrollbar = gtk_hscrollbar_new(adjustment);
+  gtk_table_attach(table,
+		   (GtkWidget *) wave_editor->hscrollbar,
+		   1, 2,
+		   3, 4,
+		   GTK_FILL, GTK_FILL,
+		   0, 0);
+  
+  /* notebook */
+  wave_editor->notebook = g_object_new(AGS_TYPE_NOTEBOOK,
+				       "homogeneous", FALSE,
+				       "spacing", 0,
+				       "prefix", i18n("line"),
+				       NULL);
+  gtk_table_attach(table,
+		   (GtkWidget *) wave_editor->notebook,
+		   0, 3,
+		   0, 1,
+		   GTK_FILL | GTK_EXPAND, GTK_FILL,
+		   0, 0);
+
+  /* ruler */
+  wave_editor->ruler = ags_ruler_new();
+  gtk_table_attach(table,
+		   (GtkWidget *) wave_editor->ruler,
+		   1, 2,
+		   1, 2,
+		   GTK_FILL | GTK_EXPAND, GTK_FILL,
+		   0, 0);
+
+
+  /* level */
+  wave_editor->scrolled_level_box = ags_scrolled_level_box_new();
+
+  wave_editor->scrolled_level_box->level_box = ags_vlevel_box_new();
+  gtk_container_add(wave_editor->scrolled_level_box->viewport,
+		    wave_editor->scrolled_level_box->level_box);
+
+  gtk_table_attach(table,
+		   (GtkWidget *) wave_editor->scrolled_level_box,
+		   0, 1,
+		   2, 3,
+		   GTK_FILL, GTK_FILL,
+		   0, 0);
+
+  /* wave edit */
+  wave_editor->scrolled_wave_edit_box = ags_scrolled_wave_edit_box_new();
+
+  wave_editor->scrolled_wave_edit_box->wave_edit_box = ags_vwave_edit_box_new();
+  gtk_container_add(wave_editor->scrolled_wave_edit_box->viewport,
+		    wave_editor->scrolled_wave_edit_box->wave_edit_box);
+
+  gtk_table_attach(table,
+		   (GtkWidget *) wave_editor->scrolled_wave_edit_box,
+		   1, 2,
+		   2, 3,
+		   GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND,
+		   0, 0);
+
+  gtk_widget_set_events(GTK_WIDGET(wave_editor->scrolled_wave_edit_box->viewport), GDK_EXPOSURE_MASK
+			| GDK_LEAVE_NOTIFY_MASK
+			| GDK_BUTTON_PRESS_MASK
+			| GDK_BUTTON_RELEASE_MASK
+			| GDK_POINTER_MOTION_MASK
+			| GDK_POINTER_MOTION_HINT_MASK
+			| GDK_CONTROL_MASK);
 }
 
 void
diff --git a/ags/X/ags_wave_editor.h b/ags/X/ags_wave_editor.h
index 9adc607..bdabc3e 100644
--- a/ags/X/ags_wave_editor.h
+++ b/ags/X/ags_wave_editor.h
@@ -29,9 +29,11 @@
 #include <ags/libags-audio.h>
 #include <ags/libags-gui.h>
 
+#include <ags/X/ags_machine.h>
+
 #include <ags/X/editor/ags_wave_toolbar.h>
 #include <ags/X/editor/ags_machine_selector.h>
-#include <ags/X/editor/ags_level.h>
+#include <ags/X/editor/ags_scrolled_wave_edit_box.h>
 #include <ags/X/editor/ags_wave_edit.h>
 
 #define AGS_TYPE_WAVE_EDITOR                (ags_wave_editor_get_type())
@@ -41,42 +43,51 @@
 #define AGS_IS_WAVE_EDITOR_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_WAVE_EDITOR))
 #define AGS_WAVE_EDITOR_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS (obj, AGS_TYPE_WAVE_EDITOR, AgsWaveEditorClass))
 
-#define AGS_WAVE_EDITOR_CHILD(ptr) ((AgsWaveEditorChild *)(ptr))
+#define AGS_WAVE_EDITOR_MAX_VALUE_COUNT (64 * 16 * 16 * 1200)
+#define AGS_WAVE_EDITOR_MAX_CONTROLS (64 * 16 * 16 * 1200)
 
-#define AGS_WAVE_EDITOR_DEFAULT_VERSION "1.2.0"
-#define AGS_WAVE_EDITOR_DEFAULT_BUILD_ID "Mon Nov 20 07:28:21 UTC 2017"
+#define AGS_WAVE_EDITOR_DEFAULT_VERSION "1.4.0"
+#define AGS_WAVE_EDITOR_DEFAULT_BUILD_ID "Thu Jan  4 19:47:23 UTC 2018"
 
 typedef struct _AgsWaveEditor AgsWaveEditor;
 typedef struct _AgsWaveEditorClass AgsWaveEditorClass;
   
 typedef enum{
-  AGS_WAVE_EDITOR_CONNECTED    = 1,
+  AGS_WAVE_EDITOR_CONNECTED                 = 1,
+  AGS_WAVE_EDITOR_RESET_AUDIO_HSCROLLBAR    = 1 <<  1,
+  AGS_WAVE_EDITOR_RESET_OUTPUT_HSCROLLBAR   = 1 <<  2,
+  AGS_WAVE_EDITOR_RESET_INPUT_HSCROLLBAR    = 1 <<  3,
+  AGS_WAVE_EDITOR_PASTE_MATCH_LINE          = 1 <<  4,
+  AGS_WAVE_EDITOR_PASTE_NO_DUPLICATES       = 1 <<  5,
 }AgsWaveEditorFlags;
 
 struct _AgsWaveEditor
 {
   GtkVBox vbox;
-
+  
   guint flags;
   
   gchar *version;
   gchar *build_id;
 
+  guint tact_counter;
+  gdouble current_tact;
+
   GObject *soundcard;
-  
+
+  GtkHPaned *paned;
+
   AgsMachineSelector *machine_selector;
   AgsMachine *selected_machine;
 
   AgsWaveToolbar *wave_toolbar;
 
-  GtkTable *table;
-
   AgsNotebook *notebook;
-  AgsLevel *level;
-  GtkWidget *wave_edit;
-
-  guint tact_counter;
-  gdouble current_tact;
+  AgsRuler *ruler;
+  AgsScrolledLevelBox *scrolled_level_box;
+  AgsScrolledWaveEditBox *scrolled_wave_edit_box;
+  GtkVScrollbar *vscrollbar;
+  GtkHScrollbar *hscrollbar;
 };
 
 struct _AgsWaveEditorClass
@@ -89,8 +100,16 @@ struct _AgsWaveEditorClass
 
 GType ags_wave_editor_get_type(void);
 
+void ags_wave_editor_reset_audio_scrollbar(AgsWaveEditor *wave_editor);
+void ags_wave_editor_reset_output_scrollbar(AgsWaveEditor *wave_editor);
+void ags_wave_editor_reset_input_scrollbar(AgsWaveEditor *wave_editor);
+
 void ags_wave_editor_machine_changed(AgsWaveEditor *wave_editor,
-					   AgsMachine *machine);
+				     AgsMachine *machine);
+
+void ags_wave_editor_select_region(AgsWaveEditor *wave_editor,
+				   guint x0, gdouble y0,
+				   guint x1, gdouble y1);
 
 void ags_wave_editor_select_all(AgsWaveEditor *wave_editor);
 
diff --git a/ags/X/ags_window.c b/ags/X/ags_window.c
index d683d22..1aadd90 100644
--- a/ags/X/ags_window.c
+++ b/ags/X/ags_window.c
@@ -21,8 +21,9 @@
 #include <ags/X/ags_window_callbacks.h>
 
 #include <ags/libags.h>
+#include <ags/libags-audio.h>
 
-#include <ags/X/ags_xorg_application_context.h>
+#include <ags/X/ags_ui_provider.h>
 
 #include <ags/X/machine/ags_panel.h>
 #include <ags/X/machine/ags_mixer.h>
@@ -191,6 +192,7 @@ void
 ags_window_init(AgsWindow *window)
 {
   GtkVBox *vbox;
+  GtkViewport *viewport;
   GtkWidget *scrolled_window;
 
   gchar *str;
@@ -246,12 +248,23 @@ ags_window_init(AgsWindow *window)
 
   /* vpaned and scrolled window */
   window->paned = (GtkVPaned *) gtk_vpaned_new();
-  gtk_box_pack_start((GtkBox*) vbox, (GtkWidget*) window->paned, TRUE, TRUE, 0);
-
-  scrolled_window = (GtkWidget *) gtk_scrolled_window_new(NULL, NULL);
+  gtk_box_pack_start((GtkBox*) vbox,
+		     (GtkWidget*) window->paned,
+		     TRUE, TRUE,
+		     0);
+
+  viewport = gtk_viewport_new(NULL,
+			      NULL);
+  g_object_set(viewport,
+	       "shadow-type", GTK_SHADOW_NONE,
+	       NULL);
   gtk_paned_pack1((GtkPaned *) window->paned,
-		  scrolled_window,
+		  viewport,
 		  TRUE, TRUE);
+  
+  scrolled_window = (GtkWidget *) gtk_scrolled_window_new(NULL, NULL);
+  gtk_container_add(viewport,
+		    scrolled_window);
 
   /* machines rack */
   window->machines = (GtkVBox *) gtk_vbox_new(FALSE, 0);
@@ -262,13 +275,21 @@ ags_window_init(AgsWindow *window)
   window->selected = NULL;
 
   /* editor */
+  viewport = gtk_viewport_new(NULL,
+			      NULL);
+  g_object_set(viewport,
+	       "shadow-type", GTK_SHADOW_NONE,
+	       NULL);
+  gtk_paned_pack2((GtkPaned *) window->paned,
+		  (GtkWidget *) viewport,
+		  TRUE, TRUE);
+
   window->notation_editor = g_object_new(AGS_TYPE_NOTATION_EDITOR,
 					 "homogeneous", FALSE,
 					 "spacing", 0,
 					 NULL);
-  gtk_paned_pack2((GtkPaned *) window->paned,
-		  (GtkWidget *) window->notation_editor,
-		  TRUE, TRUE);
+  gtk_container_add(viewport,
+		    window->notation_editor);
 
   /* navigation */
   window->navigation = g_object_new(AGS_TYPE_NAVIGATION,
@@ -284,6 +305,8 @@ ags_window_init(AgsWindow *window)
 
   window->automation_window = ags_automation_window_new((GtkWidget *) window);
 
+  window->wave_window = ags_wave_window_new((GtkWidget *) window);
+  
   window->export_window = (AgsExportWindow *) g_object_new(AGS_TYPE_EXPORT_WINDOW,
 							   "main-window", window,
 							   NULL);
@@ -749,7 +772,7 @@ ags_window_load_file_timeout(AgsWindow *window)
   gui_thread = NULL;
   
   if(window->application_context != NULL){
-    gui_thread = AGS_XORG_APPLICATION_CONTEXT(window->application_context)->gui_thread;
+    gui_thread = ags_ui_provider_get_gui_thread(AGS_UI_PROVIDER(window->application_context));
   }
   
   if(gui_thread != NULL &&
diff --git a/ags/X/ags_window.h b/ags/X/ags_window.h
index dcbd60b..0267011 100644
--- a/ags/X/ags_window.h
+++ b/ags/X/ags_window.h
@@ -32,6 +32,7 @@
 #include <ags/X/ags_navigation.h>
 #include <ags/X/ags_export_window.h>
 #include <ags/X/ags_automation_window.h>
+#include <ags/X/ags_wave_window.h>
 #include <ags/X/ags_preferences.h>
 #include <ags/X/ags_history_browser.h>
 
@@ -86,6 +87,7 @@ struct _AgsWindow
   GList *dialog;
   
   AgsAutomationWindow *automation_window;
+  AgsWaveWindow *wave_window;
 
   AgsExportWindow *export_window;
 
diff --git a/ags/X/ags_xorg_application_context.c b/ags/X/ags_xorg_application_context.c
index 3940253..3855ad6 100644
--- a/ags/X/ags_xorg_application_context.c
+++ b/ags/X/ags_xorg_application_context.c
@@ -112,6 +112,15 @@ GList* ags_xorg_application_context_get_distributed_manager(AgsSoundProvider *so
 GtkWidget* ags_xorg_application_context_get_window(AgsUiProvider *ui_provider);
 void ags_xorg_application_context_set_window(AgsUiProvider *ui_provider,
 					     GtkWidget *widget);
+AgsThread* ags_xorg_application_context_get_gui_thread(AgsUiProvider *ui_provider);
+void ags_xorg_application_context_set_gui_thread(AgsUiProvider *ui_provider,
+						 AgsThread *gui_thread);
+gboolean ags_xorg_application_context_get_show_animation(AgsUiProvider *ui_provider);
+void ags_xorg_application_context_set_show_animation(AgsUiProvider *ui_provider,
+						     gboolean do_show_animation);
+gboolean ags_xorg_application_context_get_gui_ready(AgsUiProvider *ui_provider);
+void ags_xorg_application_context_set_gui_ready(AgsUiProvider *ui_provider,
+						gboolean is_gui_ready);
 void ags_xorg_application_context_dispose(GObject *gobject);
 void ags_xorg_application_context_finalize(GObject *gobject);
 
@@ -365,6 +374,15 @@ ags_xorg_application_context_ui_provider_interface_init(AgsUiProviderInterface *
 {
   ui_provider->get_window = ags_xorg_application_context_get_window;
   ui_provider->set_window = ags_xorg_application_context_set_window;
+
+  ui_provider->get_gui_thread = ags_xorg_application_context_get_gui_thread;
+  ui_provider->set_gui_thread = ags_xorg_application_context_set_gui_thread;
+  
+  ui_provider->get_show_animation = ags_xorg_application_context_get_show_animation;
+  ui_provider->set_show_animation = ags_xorg_application_context_set_show_animation;
+
+  ui_provider->get_gui_ready = ags_xorg_application_context_get_gui_ready;
+  ui_provider->set_gui_ready = ags_xorg_application_context_set_gui_ready;
 }
 
 void
@@ -807,6 +825,47 @@ ags_xorg_application_context_set_window(AgsUiProvider *ui_provider,
   AGS_XORG_APPLICATION_CONTEXT(ui_provider)->window = widget;
 }
 
+AgsThread*
+ags_xorg_application_context_get_gui_thread(AgsUiProvider *ui_provider)
+{
+  return(AGS_XORG_APPLICATION_CONTEXT(ui_provider)->gui_thread);
+}
+
+void
+ags_xorg_application_context_set_gui_thread(AgsUiProvider *ui_provider,
+					    AgsThread *gui_thread)
+{
+  AGS_XORG_APPLICATION_CONTEXT(ui_provider)->gui_thread = gui_thread;
+}
+
+gboolean
+ags_xorg_application_context_get_show_animation(AgsUiProvider *ui_provider)
+{
+  return(g_atomic_int_get(&(AGS_XORG_APPLICATION_CONTEXT(ui_provider)->show_animation)));
+}
+
+void
+ags_xorg_application_context_set_show_animation(AgsUiProvider *ui_provider,
+						gboolean do_show_animation)
+{
+  g_atomic_int_set(&(AGS_XORG_APPLICATION_CONTEXT(ui_provider)->show_animation),
+		   do_show_animation);
+}
+
+gboolean
+ags_xorg_application_context_get_gui_ready(AgsUiProvider *ui_provider)
+{
+  return(g_atomic_int_get(&(AGS_XORG_APPLICATION_CONTEXT(ui_provider)->gui_ready)));
+}
+
+void
+ags_xorg_application_context_set_gui_ready(AgsUiProvider *ui_provider,
+					   gboolean is_gui_ready)
+{
+  g_atomic_int_set(&(AGS_XORG_APPLICATION_CONTEXT(ui_provider)->gui_ready),
+		   is_gui_ready);
+}
+  
 void
 ags_xorg_application_context_load_config(AgsApplicationContext *application_context)
 {
@@ -868,6 +927,7 @@ ags_xorg_application_context_prepare(AgsApplicationContext *application_context)
   /* AgsGuiThread */
   gui_thread = 
     xorg_application_context->gui_thread = (AgsThread *) ags_gui_thread_new();
+  g_object_ref(gui_thread);
   ags_thread_add_child_extended(AGS_THREAD(audio_loop),
   				(AgsThread *) gui_thread,
   				TRUE, TRUE);
@@ -1566,6 +1626,7 @@ ags_xorg_application_context_setup(AgsApplicationContext *application_context)
     /* default soundcard thread */
     if(xorg_application_context->soundcard_thread == NULL){
       xorg_application_context->soundcard_thread = soundcard_thread;
+      g_object_ref(soundcard_thread);
     }
 
     /* default export thread */
diff --git a/ags/X/editor/ags_automation_edit.c b/ags/X/editor/ags_automation_edit.c
index c987274..a11c5c7 100644
--- a/ags/X/editor/ags_automation_edit.c
+++ b/ags/X/editor/ags_automation_edit.c
@@ -384,6 +384,7 @@ ags_automation_edit_init(AgsAutomationEdit *automation_edit)
   automation_edit->flags = 0;
   automation_edit->mode = AGS_AUTOMATION_EDIT_NO_EDIT_MODE;
 
+  automation_edit->button_mask = 0;
   automation_edit->key_mask = 0;
   
   automation_edit->note_offset = 0;
@@ -1653,7 +1654,7 @@ ags_automation_edit_draw_cursor(AgsAutomationEdit *automation_edit)
   zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) automation_toolbar->zoom));
 
   /* get offset */
-  x = ((double) automation_edit->cursor_position_x) - GTK_RANGE(automation_edit->hscrollbar)->adjustment->value;
+  x = ((double) automation_edit->cursor_position_x) - (GTK_RANGE(automation_edit->hscrollbar)->adjustment->value * zoom_factor);
   
   if((AGS_AUTOMATION_EDIT_LOGARITHMIC & (automation_edit->flags)) != 0){
     y = GTK_WIDGET(automation_edit->drawing_area)->allocation.height - ((((double) exp(automation_edit->cursor_position_y) / c_range) * GTK_WIDGET(automation_edit->drawing_area)->allocation.height) - GTK_RANGE(automation_edit->vscrollbar)->adjustment->value);
diff --git a/ags/X/editor/ags_automation_edit.h b/ags/X/editor/ags_automation_edit.h
index d183a21..53cde4b 100644
--- a/ags/X/editor/ags_automation_edit.h
+++ b/ags/X/editor/ags_automation_edit.h
@@ -87,6 +87,10 @@ typedef enum{
 }AgsAutomationEditMode;
 
 typedef enum{
+  AGS_AUTOMATION_EDIT_BUTTON_1            = 1,
+}AgsAutomationEditButtonMask;
+
+typedef enum{
   AGS_AUTOMATION_EDIT_KEY_L_CONTROL       = 1,
   AGS_AUTOMATION_EDIT_KEY_R_CONTROL       = 1 <<  1,
   AGS_AUTOMATION_EDIT_KEY_L_SHIFT         = 1 <<  2,
@@ -99,7 +103,8 @@ struct _AgsAutomationEdit
 
   guint flags;
   guint mode;
-  
+
+  guint button_mask;
   guint key_mask;
   
   guint note_offset;
diff --git a/ags/X/editor/ags_automation_edit_callbacks.c b/ags/X/editor/ags_automation_edit_callbacks.c
index d1cd446..2825f2b 100644
--- a/ags/X/editor/ags_automation_edit_callbacks.c
+++ b/ags/X/editor/ags_automation_edit_callbacks.c
@@ -80,7 +80,7 @@ ags_automation_edit_drawing_area_button_press_event(GtkWidget *widget, GdkEventB
     zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) automation_toolbar->zoom));
 
     /* cursor position */
-    automation_edit->cursor_position_x = (guint) zoom_factor * ((event->x + GTK_RANGE(automation_edit->hscrollbar)->adjustment->value) / automation_edit->control_width);
+    automation_edit->cursor_position_x = (guint) (zoom_factor * (event->x + GTK_RANGE(automation_edit->hscrollbar)->adjustment->value)) / automation_edit->control_width;
     
     if((AGS_AUTOMATION_EDIT_LOGARITHMIC & (automation_edit->flags)) != 0){
       automation_edit->cursor_position_y = log(((GTK_WIDGET(automation_edit->drawing_area)->allocation.height - event->y) / g_range) * c_range);
@@ -114,7 +114,7 @@ ags_automation_edit_drawing_area_button_press_event(GtkWidget *widget, GdkEventB
     zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) automation_toolbar->zoom));
 
     /* acceleration */
-    acceleration->x = (guint) zoom_factor * ((event->x + GTK_RANGE(automation_edit->hscrollbar)->adjustment->value));
+    acceleration->x = (guint) (zoom_factor * (event->x + GTK_RANGE(automation_edit->hscrollbar)->adjustment->value));
     
     if((AGS_AUTOMATION_EDIT_LOGARITHMIC & (automation_edit->flags)) != 0){
       acceleration->y = log(((GTK_WIDGET(automation_edit->drawing_area)->allocation.height - event->y) / g_range) * c_range);
@@ -157,6 +157,8 @@ ags_automation_edit_drawing_area_button_press_event(GtkWidget *widget, GdkEventB
 
   if((machine = automation_editor->selected_machine) != NULL &&
      event->button == 1){    
+    automation_edit->button_mask = AGS_AUTOMATION_EDIT_BUTTON_1;
+    
     if(automation_toolbar->selected_edit_mode == automation_toolbar->position){
       automation_edit->mode = AGS_AUTOMATION_EDIT_POSITION_CURSOR;
 
@@ -209,7 +211,7 @@ ags_automation_edit_drawing_area_button_release_event(GtkWidget *widget, GdkEven
     zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) automation_toolbar->zoom));
 
     /* cursor position */
-    automation_edit->cursor_position_x = (guint) zoom_factor * ((event->x + GTK_RANGE(automation_edit->hscrollbar)->adjustment->value) / automation_edit->control_width);
+    automation_edit->cursor_position_x = (guint) (zoom_factor * (event->x + GTK_RANGE(automation_edit->hscrollbar)->adjustment->value)) / automation_edit->control_width;
     
     if((AGS_AUTOMATION_EDIT_LOGARITHMIC & (automation_edit->flags)) != 0){
       automation_edit->cursor_position_y = log(((GTK_WIDGET(automation_edit->drawing_area)->allocation.height - event->y) / g_range) * c_range);
@@ -248,7 +250,7 @@ ags_automation_edit_drawing_area_button_release_event(GtkWidget *widget, GdkEven
     zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) automation_toolbar->zoom));
 
     /* acceleration */
-    acceleration->x = (guint) zoom_factor * ((event->x + GTK_RANGE(automation_edit->hscrollbar)->adjustment->value));
+    acceleration->x = (guint) (zoom_factor * (event->x + GTK_RANGE(automation_edit->hscrollbar)->adjustment->value));
     
     if((AGS_AUTOMATION_EDIT_LOGARITHMIC & (automation_edit->flags)) != 0){
       acceleration->y = log(((GTK_WIDGET(automation_edit->drawing_area)->allocation.height - event->y) / g_range) * c_range);
@@ -349,9 +351,13 @@ ags_automation_edit_drawing_area_button_release_event(GtkWidget *widget, GdkEven
   automation_toolbar = automation_editor->automation_toolbar;
 
   if((machine = automation_editor->selected_machine) != NULL &&
-     event->button == 1){    
+     event->button == 1){
+    automation_edit->button_mask &= (~AGS_AUTOMATION_EDIT_BUTTON_1);
+    
     if(automation_edit->mode == AGS_AUTOMATION_EDIT_POSITION_CURSOR){
       ags_automation_edit_drawing_area_button_release_position_cursor();
+
+      automation_edit->mode = AGS_AUTOMATION_EDIT_NO_EDIT_MODE;
     }else if(automation_edit->mode == AGS_AUTOMATION_EDIT_ADD_ACCELERATION){
       ags_automation_edit_drawing_area_button_release_add_acceleration();
 
@@ -481,7 +487,8 @@ ags_automation_edit_drawing_area_motion_notify_event(GtkWidget *widget, GdkEvent
 
   gtk_widget_grab_focus((GtkWidget *) automation_edit->drawing_area);
 
-  if((machine = automation_editor->selected_machine) != NULL){
+  if((machine = automation_editor->selected_machine) != NULL &&
+     (AGS_AUTOMATION_EDIT_BUTTON_1 & (automation_edit->button_mask)) != 0){
     if(automation_edit->mode == AGS_AUTOMATION_EDIT_POSITION_CURSOR){
       ags_automation_edit_drawing_area_motion_notify_position_cursor();
     }else if(automation_edit->mode == AGS_AUTOMATION_EDIT_ADD_ACCELERATION){
diff --git a/ags/X/editor/ags_level.c b/ags/X/editor/ags_level.c
deleted file mode 100644
index fb67cf4..0000000
--- a/ags/X/editor/ags_level.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/* GSequencer - Advanced GTK Sequencer
- * Copyright (C) 2005-2017 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/X/editor/ags_level.h>
-#include <ags/X/editor/ags_level_callbacks.h>
-
-#include <ags/object/ags_connectable.h>
-
-#include <math.h>
-
-void ags_level_class_init(AgsLevelClass *level);
-void ags_level_connectable_interface_init(AgsConnectableInterface *connectable);
-void ags_level_init(AgsLevel *level);
-void ags_level_connect(AgsConnectable *connectable);
-void ags_level_disconnect(AgsConnectable *connectable);
-
-/**
- * SECTION:ags_level
- * @short_description: volume level widget
- * @title: AgsLevel
- * @section_id:
- * @include: ags/X/editor/ags_level.h
- *
- * The #AgsLevel draws you a volume level.
- */
-
-GtkStyle *level_style = NULL;
-
-GType
-ags_level_get_type(void)
-{
-  static GType ags_type_level = 0;
-
-  if (!ags_type_level){
-    static const GTypeInfo ags_level_info = {
-      sizeof (AgsLevelClass),
-      NULL, /* base_init */
-      NULL, /* base_finalize */
-      (GClassInitFunc) ags_level_class_init,
-      NULL, /* class_finalize */
-      NULL, /* class_data */
-      sizeof (AgsLevel),
-      0,    /* n_preallocs */
-      (GInstanceInitFunc) ags_level_init,
-    };
-
-    static const GInterfaceInfo ags_connectable_interface_info = {
-      (GInterfaceInitFunc) ags_level_connectable_interface_init,
-      NULL, /* interface_finalize */
-      NULL, /* interface_data */
-    };
-
-    ags_type_level = g_type_register_static(GTK_TYPE_DRAWING_AREA,
-					    "AgsLevel", &ags_level_info,
-					    0);
-    
-    g_type_add_interface_static(ags_type_level,
-				AGS_TYPE_CONNECTABLE,
-				&ags_connectable_interface_info);
-  }
-
-  return (ags_type_level);
-}
-
-void
-ags_level_class_init(AgsLevelClass *level)
-{
-}
-
-void
-ags_level_connectable_interface_init(AgsConnectableInterface *connectable)
-{
-  connectable->is_ready = NULL;
-  connectable->is_connected = NULL;
-  connectable->connect = ags_level_connect;
-  connectable->disconnect = ags_level_disconnect;
-}
-
-void
-ags_level_init(AgsLevel *level)
-{
-  if(level_style == NULL){
-    level_style = gtk_style_copy(gtk_widget_get_style(level));
-  }
-
-  gtk_widget_set_style((GtkWidget *) level,
-		       level_style);
-  gtk_widget_set_size_request((GtkWidget *) level,
-			      60, -1);
-  gtk_widget_set_events(GTK_WIDGET(level), GDK_EXPOSURE_MASK
-			| GDK_LEAVE_NOTIFY_MASK
-			| GDK_BUTTON_PRESS_MASK
-			| GDK_BUTTON_RELEASE_MASK);
-}
-
-void
-ags_level_connect(AgsConnectable *connectable)
-{
-  AgsLevel *level;
-
-  level = AGS_LEVEL(connectable);
-
-  g_signal_connect((GObject *) level, "expose_event",
-  		   G_CALLBACK(ags_level_expose_event), (gpointer) level);
-
-  g_signal_connect((GObject *) level, "configure_event",
-  		   G_CALLBACK(ags_level_configure_event), (gpointer) level);
-}
-
-void
-ags_level_disconnect(AgsConnectable *connectable)
-{
-  AgsLevel *level;
-
-  level = AGS_LEVEL(connectable);
-
-  //TODO:JK: implement me
-}
-
-void
-ags_level_paint(AgsLevel *level,
-		cairo_t *cr)
-{
-  if(!AGS_IS_LEVEL(level) ||
-     cr == NULL){
-    return;
-  }
-
-  //TODO:JK: implement me
-}
-
-/**
- * ags_level_new:
- *
- * Create a new #AgsLevel.
- *
- * Returns: a new #AgsLevel
- *
- * Since: 1.2.0
- */
-AgsLevel*
-ags_level_new()
-{
-  AgsLevel *level;
-
-  level = (AgsLevel *) g_object_new(AGS_TYPE_LEVEL, NULL);
-
-  return(level);
-}
diff --git a/ags/X/editor/ags_level_callbacks.c b/ags/X/editor/ags_level_callbacks.c
deleted file mode 100644
index 15d5255..0000000
--- a/ags/X/editor/ags_level_callbacks.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/* GSequencer - Advanced GTK Sequencer
- * Copyright (C) 2005-2017 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/X/editor/ags_level_callbacks.h>
-
-#include <math.h>
-
-gboolean
-ags_level_expose_event(GtkWidget *widget, GdkEventExpose *event, AgsLevel *level)
-{
-  cairo_t *cr;
-  
-  if(!gtk_widget_get_visible(widget) ||
-     !gtk_widget_is_drawable(widget) ||
-     !gtk_widget_get_mapped(widget) ||
-     !gtk_widget_get_realized(widget)){
-    return(TRUE);
-  }
-
-  cr = gdk_cairo_create(widget->window);
-
-  ags_level_paint(level,
-		  cr);
-
-  cairo_surface_mark_dirty(cairo_get_target(cr));
-  cairo_destroy(cr);
-
-  return(TRUE);
-}
-
-gboolean
-ags_level_configure_event(GtkWidget *widget, GdkEventConfigure *event, AgsLevel *level)
-{
-  cairo_t *cr;
-
-  if(!gtk_widget_get_visible(widget) ||
-     !gtk_widget_is_drawable(widget) ||
-     !gtk_widget_get_mapped(widget) ||
-     !gtk_widget_get_realized(widget)){
-    return(FALSE);
-  }
-
-  cr = gdk_cairo_create(widget->window);
-
-  ags_level_paint(level,
-		  cr);
-
-  cairo_surface_mark_dirty(cairo_get_target(cr));
-  cairo_destroy(cr);
-
-  return(FALSE);
-}
diff --git a/ags/X/editor/ags_level_callbacks.h b/ags/X/editor/ags_level_callbacks.h
deleted file mode 100644
index 4af2e8d..0000000
--- a/ags/X/editor/ags_level_callbacks.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* GSequencer - Advanced GTK Sequencer
- * Copyright (C) 2005-2017 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_LEVEL_CALLBACKS_H__
-#define __AGS_LEVEL_CALLBACKS_H__
-
-#include <glib.h>
-#include <glib-object.h>
-
-#include <gtk/gtk.h>
-
-#include <ags/X/editor/ags_level.h>
-
-gboolean ags_level_expose_event(GtkWidget *widget, GdkEventExpose *event, AgsLevel *level); 
-gboolean ags_level_configure_event(GtkWidget *widget, GdkEventConfigure *event, AgsLevel *level); 
-
-#endif /*__AGS_LEVEL_CALLBACKS_H__*/
diff --git a/ags/X/editor/ags_notation_edit.c b/ags/X/editor/ags_notation_edit.c
index 02496d5..ab9444a 100644
--- a/ags/X/editor/ags_notation_edit.c
+++ b/ags/X/editor/ags_notation_edit.c
@@ -225,6 +225,7 @@ ags_notation_edit_init(AgsNotationEdit *notation_edit)
 			  AGS_NOTATION_EDIT_SHOW_HSCROLLBAR);
   notation_edit->mode = AGS_NOTATION_EDIT_NO_EDIT_MODE;
 
+  notation_edit->button_mask = 0;
   notation_edit->key_mask = 0;
 
   notation_edit->note_offset = 0;
@@ -1338,7 +1339,7 @@ ags_notation_edit_draw_cursor(AgsNotationEdit *notation_edit)
   zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) notation_toolbar->zoom));
 
   /* get offset */
-  x = ((double) notation_edit->cursor_position_x * (double) notation_edit->control_width) - GTK_RANGE(notation_edit->hscrollbar)->adjustment->value;
+  x = ((double) notation_edit->cursor_position_x * (double) notation_edit->control_width) - (GTK_RANGE(notation_edit->hscrollbar)->adjustment->value * zoom_factor);
   y = ((double) notation_edit->cursor_position_y * (double) notation_edit->control_height) - GTK_RANGE(notation_edit->vscrollbar)->adjustment->value;
 
   width = (double) notation_edit->control_width;
@@ -1427,15 +1428,17 @@ ags_notation_edit_draw_selection(AgsNotationEdit *notation_edit)
   }
 
   if(notation_edit->selection_y0 < notation_edit->selection_y1){
-    y = ((double) notation_edit->selection_y0) - GTK_RANGE(notation_edit->hscrollbar)->adjustment->value;
+    y = ((double) notation_edit->selection_y0) - GTK_RANGE(notation_edit->vscrollbar)->adjustment->value;
     height = ((double) notation_edit->selection_y1 - (double) notation_edit->selection_y0);
   }else{
-    y = ((double) notation_edit->selection_y1) - GTK_RANGE(notation_edit->hscrollbar)->adjustment->value;
+    y = ((double) notation_edit->selection_y1) - GTK_RANGE(notation_edit->vscrollbar)->adjustment->value;
     height = ((double) notation_edit->selection_y0 - (double) notation_edit->selection_y1);
   }
 
   /* clip */
   if(x < 0.0){
+    width += x;
+
     x = 0.0;
   }else if(x > GTK_WIDGET(notation_edit->drawing_area)->allocation.width){
     cairo_destroy(cr);
@@ -1448,6 +1451,8 @@ ags_notation_edit_draw_selection(AgsNotationEdit *notation_edit)
   }
   
   if(y < 0.0){
+    height += y;
+
     y = 0.0;
   }else if(y > GTK_WIDGET(notation_edit->drawing_area)->allocation.height){
     cairo_destroy(cr);
@@ -1640,6 +1645,7 @@ void
 ags_notation_edit_draw_notation(AgsNotationEdit *notation_edit)
 {
   AgsNotationEditor *notation_editor;
+  AgsNotationToolbar *notation_toolbar;
 
   GtkStyle *notation_edit_style;
   
@@ -1649,7 +1655,8 @@ ags_notation_edit_draw_notation(AgsNotationEdit *notation_edit)
 
   GList *list_notation;
   GList *list_note;
-  
+
+  gdouble zoom;
   guint x0, x1;
   guint y0, y1;
   guint offset;
@@ -1666,6 +1673,7 @@ ags_notation_edit_draw_notation(AgsNotationEdit *notation_edit)
 
   notation_editor = gtk_widget_get_ancestor(notation_edit,
 					    AGS_TYPE_NOTATION_EDITOR);
+  notation_toolbar = notation_editor->notation_toolbar;
 
   if(notation_editor->selected_machine == NULL){
     return;
@@ -1691,9 +1699,12 @@ ags_notation_edit_draw_notation(AgsNotationEdit *notation_edit)
     return;
   }
 
+  /* zoom */
+  zoom = exp2((double) gtk_combo_box_get_active((GtkComboBox *) notation_toolbar->zoom) - 2.0);
+
   /* get visisble region */
   x0 = GTK_RANGE(notation_edit->hscrollbar)->adjustment->value / notation_edit->control_width;
-  x1 = (GTK_RANGE(notation_edit->hscrollbar)->adjustment->value + GTK_WIDGET(notation_edit->drawing_area)->allocation.width) / notation_edit->control_width;
+  x1 = (GTK_RANGE(notation_edit->hscrollbar)->adjustment->value / notation_edit->control_width) + (GTK_WIDGET(notation_edit->drawing_area)->allocation.width * zoom);
 
   y0 = GTK_RANGE(notation_edit->vscrollbar)->adjustment->value / notation_edit->control_height;
   y1 = (GTK_RANGE(notation_edit->vscrollbar)->adjustment->value + GTK_WIDGET(notation_edit->drawing_area)->allocation.height) / notation_edit->control_height;
@@ -1719,7 +1730,7 @@ ags_notation_edit_draw_notation(AgsNotationEdit *notation_edit)
       notation = AGS_NOTATION(list_notation->data);
       
       if(notation->timestamp != NULL &&
-	 AGS_TIMESTAMP(notation->timestamp)->timer.ags_offset.offset > x1){
+	 AGS_TIMESTAMP(notation->timestamp)->timer.ags_offset.offset > x1){	
 	break;
       }
 
diff --git a/ags/X/editor/ags_notation_edit.h b/ags/X/editor/ags_notation_edit.h
index dad5bbe..464f79d 100644
--- a/ags/X/editor/ags_notation_edit.h
+++ b/ags/X/editor/ags_notation_edit.h
@@ -71,6 +71,10 @@ typedef enum{
 }AgsNotationEditMode;
 
 typedef enum{
+  AGS_NOTATION_EDIT_BUTTON_1            = 1,
+}AgsNotationEditButtonMask;
+
+typedef enum{
   AGS_NOTATION_EDIT_KEY_L_CONTROL       = 1,
   AGS_NOTATION_EDIT_KEY_R_CONTROL       = 1 <<  1,
   AGS_NOTATION_EDIT_KEY_L_SHIFT         = 1 <<  2,
@@ -83,7 +87,8 @@ struct _AgsNotationEdit
 
   guint flags;
   guint mode;
-  
+
+  guint button_mask;
   guint key_mask;
 
   guint note_offset;
diff --git a/ags/X/editor/ags_notation_edit_callbacks.c b/ags/X/editor/ags_notation_edit_callbacks.c
index 0501444..4e5ca2f 100644
--- a/ags/X/editor/ags_notation_edit_callbacks.c
+++ b/ags/X/editor/ags_notation_edit_callbacks.c
@@ -70,7 +70,7 @@ ags_notation_edit_drawing_area_button_press_event(GtkWidget *widget, GdkEventBut
     zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) notation_toolbar->zoom));
 
     /* cursor position */
-    notation_edit->cursor_position_x = (guint) zoom_factor * ((event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value) / notation_edit->control_width);
+    notation_edit->cursor_position_x = (guint) (zoom_factor * (event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value)) / notation_edit->control_width;
     notation_edit->cursor_position_x = zoom_factor * floor(notation_edit->cursor_position_x / zoom_factor);
     
     notation_edit->cursor_position_y = (guint) ((event->y + GTK_RANGE(notation_edit->vscrollbar)->adjustment->value) / notation_edit->control_height);
@@ -91,7 +91,7 @@ ags_notation_edit_drawing_area_button_press_event(GtkWidget *widget, GdkEventBut
     zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) notation_toolbar->zoom));
 
     /* note */
-    note->x[0] = (guint) zoom_factor * ((event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value) / notation_edit->control_width);
+    note->x[0] = (guint) (zoom_factor * (event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value)) / notation_edit->control_width;
     note->x[0] = zoom_factor * floor(note->x[0] / zoom_factor);
 
     if((AGS_NOTATION_EDITOR_PATTERN_MODE & (notation_editor->flags)) == 0){
@@ -136,9 +136,11 @@ ags_notation_edit_drawing_area_button_press_event(GtkWidget *widget, GdkEventBut
 
   if((machine = notation_editor->selected_machine) != NULL &&
      event->button == 1){    
+    notation_edit->button_mask |= AGS_NOTATION_EDIT_BUTTON_1;
+    
     if(notation_toolbar->selected_edit_mode == notation_toolbar->position){
       notation_edit->mode = AGS_NOTATION_EDIT_POSITION_CURSOR;
-
+      
       ags_notation_edit_drawing_area_button_press_position_cursor();
     }else if(notation_toolbar->selected_edit_mode == notation_toolbar->edit){
       notation_edit->mode = AGS_NOTATION_EDIT_ADD_NOTE;
@@ -178,7 +180,7 @@ ags_notation_edit_drawing_area_button_release_event(GtkWidget *widget, GdkEventB
     zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) notation_toolbar->zoom));
 
     /* cursor position */
-    notation_edit->cursor_position_x = (guint) zoom_factor * ((event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value) / notation_edit->control_width);
+    notation_edit->cursor_position_x = (guint) (zoom_factor * (event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value)) / notation_edit->control_width;
     notation_edit->cursor_position_x = zoom_factor * floor(notation_edit->cursor_position_x / zoom_factor);
 
     notation_edit->cursor_position_y = (guint) ((event->y + GTK_RANGE(notation_edit->vscrollbar)->adjustment->value) / notation_edit->control_height);
@@ -205,7 +207,7 @@ ags_notation_edit_drawing_area_button_release_event(GtkWidget *widget, GdkEventB
 
     /* new x[1] */
     if((AGS_NOTATION_EDITOR_PATTERN_MODE & (notation_editor->flags)) == 0){
-      new_x = (guint) zoom_factor * ((event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value) / notation_edit->control_width);
+      new_x = (guint) (zoom_factor * (event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value)) / notation_edit->control_width;
       new_x = zoom_factor * floor((new_x + zoom_factor) / zoom_factor);
     
       if(new_x >= note->x[0] + zoom_factor){
@@ -236,7 +238,7 @@ ags_notation_edit_drawing_area_button_release_event(GtkWidget *widget, GdkEventB
     zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) notation_toolbar->zoom));
 
     /* note */
-    x = (guint) zoom_factor * ((event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value) / notation_edit->control_width);
+    x = (guint) (zoom_factor * (event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value)) / notation_edit->control_width;
     x = zoom_factor * floor(x / zoom_factor);
     
     y = (guint) ((event->y + GTK_RANGE(notation_edit->vscrollbar)->adjustment->value) / notation_edit->control_height);
@@ -255,13 +257,11 @@ ags_notation_edit_drawing_area_button_release_event(GtkWidget *widget, GdkEventB
     zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) notation_toolbar->zoom));
 
     /* region */
-    x0 = (guint) zoom_factor * (notation_edit->selection_x0 / notation_edit->control_width);
-    x0 = zoom_factor * floor(x0 / zoom_factor);
+    x0 = (guint) (zoom_factor * notation_edit->selection_x0) / notation_edit->control_width;
 
     y0 = (guint) (notation_edit->selection_y0 / notation_edit->control_height);
     
-    x1 = (guint) zoom_factor * ((event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value) / notation_edit->control_width);
-    x1 = zoom_factor * floor(x1 / zoom_factor);
+    x1 = (guint) (zoom_factor * (event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value)) / notation_edit->control_width;
     
     y1 = (guint) ((event->y + GTK_RANGE(notation_edit->vscrollbar)->adjustment->value) / notation_edit->control_height);
 
@@ -278,8 +278,12 @@ ags_notation_edit_drawing_area_button_release_event(GtkWidget *widget, GdkEventB
 
   if((machine = notation_editor->selected_machine) != NULL &&
      event->button == 1){    
+    notation_edit->button_mask &= (~AGS_NOTATION_EDIT_BUTTON_1);
+    
     if(notation_edit->mode == AGS_NOTATION_EDIT_POSITION_CURSOR){
       ags_notation_edit_drawing_area_button_release_position_cursor();
+      
+      //      notation_edit->mode = AGS_NOTATION_EDIT_NO_EDIT_MODE;
     }else if(notation_edit->mode == AGS_NOTATION_EDIT_ADD_NOTE){
       ags_notation_edit_drawing_area_button_release_add_note();
 
@@ -317,7 +321,7 @@ ags_notation_edit_drawing_area_motion_notify_event(GtkWidget *widget, GdkEventMo
     zoom_factor = exp2(6.0 - (double) gtk_combo_box_get_active((GtkComboBox *) notation_toolbar->zoom));
 
     /* cursor position */
-    notation_edit->cursor_position_x = (guint) zoom_factor * ((event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value) / notation_edit->control_width);
+    notation_edit->cursor_position_x = (guint) (zoom_factor * (event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value)) / notation_edit->control_width;
     notation_edit->cursor_position_x = zoom_factor * floor(notation_edit->cursor_position_x / zoom_factor);
 
     notation_edit->cursor_position_y = (guint) ((event->y + GTK_RANGE(notation_edit->vscrollbar)->adjustment->value) / notation_edit->control_height);
@@ -348,7 +352,7 @@ ags_notation_edit_drawing_area_motion_notify_event(GtkWidget *widget, GdkEventMo
 
     /* new x[1] */
     if((AGS_NOTATION_EDITOR_PATTERN_MODE & (notation_editor->flags)) == 0){    
-      new_x = (guint) zoom_factor * ((event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value) / notation_edit->control_width);
+      new_x = (guint) (zoom_factor * (event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value)) / notation_edit->control_width;
       new_x = zoom_factor * floor((new_x + zoom_factor) / zoom_factor);
     
       if(new_x >= note->x[0] + zoom_factor){
@@ -368,9 +372,17 @@ ags_notation_edit_drawing_area_motion_notify_event(GtkWidget *widget, GdkEventMo
 
   void ags_notation_edit_drawing_area_motion_notify_select_note()
   {
-    notation_edit->selection_x1 = (guint) event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value;
+    if(event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value >= 0.0){
+      notation_edit->selection_x1 = (guint) event->x + GTK_RANGE(notation_edit->hscrollbar)->adjustment->value;
+    }else{
+      notation_edit->selection_x1 = 0.0;
+    }
     
-    notation_edit->selection_y1 = (guint) event->y + GTK_RANGE(notation_edit->vscrollbar)->adjustment->value;
+    if(event->y + GTK_RANGE(notation_edit->vscrollbar)->adjustment->value >= 0.0){
+      notation_edit->selection_y1 = (guint) event->y + GTK_RANGE(notation_edit->vscrollbar)->adjustment->value;
+    }else{
+      notation_edit->selection_y1 = 0.0;
+    }
 
     gtk_widget_queue_draw(notation_edit);
   }
@@ -382,7 +394,8 @@ ags_notation_edit_drawing_area_motion_notify_event(GtkWidget *widget, GdkEventMo
 
   gtk_widget_grab_focus((GtkWidget *) notation_edit->drawing_area);
 
-  if((machine = notation_editor->selected_machine) != NULL){
+  if((machine = notation_editor->selected_machine) != NULL &&
+     (AGS_NOTATION_EDIT_BUTTON_1 & (notation_edit->button_mask)) != 0){
     if(notation_edit->mode == AGS_NOTATION_EDIT_POSITION_CURSOR){
       ags_notation_edit_drawing_area_motion_notify_position_cursor();
     }else if(notation_edit->mode == AGS_NOTATION_EDIT_ADD_NOTE){
diff --git a/ags/X/editor/ags_scrolled_wave_edit_box.c b/ags/X/editor/ags_scrolled_wave_edit_box.c
new file mode 100644
index 0000000..a193d66
--- /dev/null
+++ b/ags/X/editor/ags_scrolled_wave_edit_box.c
@@ -0,0 +1,376 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2017 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/X/editor/ags_scrolled_wave_edit_box.h>
+
+#include <ags/widget/ags_level.h>
+
+void ags_scrolled_wave_edit_box_class_init(AgsScrolledWaveEditBoxClass *scrolled_wave_edit_box);
+void ags_scrolled_wave_edit_box_init(AgsScrolledWaveEditBox *scrolled_wave_edit_box);
+void ags_scrolled_wave_edit_box_set_property(GObject *gobject,
+					     guint prop_id,
+					     const GValue *value,
+					     GParamSpec *param_spec);
+void ags_scrolled_wave_edit_box_get_property(GObject *gobject,
+					     guint prop_id,
+					     GValue *value,
+					     GParamSpec *param_spec);
+void ags_scrolled_wave_edit_box_finalize(GObject *gobject);
+
+void ags_scrolled_wave_edit_box_size_allocate(GtkWidget *widget,
+					      GtkAllocation *allocation);
+void ags_scrolled_wave_edit_box_size_request(GtkWidget *widget,
+					     GtkRequisition *requisition);
+
+/**
+ * SECTION:ags_scrolled_wave_edit_box
+ * @short_description: scrolled wave_edit box widget
+ * @title: AgsScrolledWaveEditBox
+ * @section_id:
+ * @include: ags/widget/ags_scrolled_wave_edit_box.h
+ *
+ * The #AgsScrolledWaveEditBox lets you to have a scrolled wave_edit box widget.
+ */
+
+enum{
+  PROP_0,
+  PROP_MARGIN_TOP,
+  PROP_MARGIN_BOTTOM,
+  PROP_MARGIN_LEFT,
+  PROP_MARGIN_RIGHT,
+};
+
+static gpointer ags_scrolled_wave_edit_box_parent_class = NULL;
+
+GType
+ags_scrolled_wave_edit_box_get_type(void)
+{
+  static GType ags_type_scrolled_wave_edit_box = 0;
+
+  if(!ags_type_scrolled_wave_edit_box){
+    static const GTypeInfo ags_scrolled_wave_edit_box_info = {
+      sizeof (AgsScrolledWaveEditBoxClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      (GClassInitFunc) ags_scrolled_wave_edit_box_class_init,
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof (AgsScrolledWaveEditBox),
+      0,    /* n_preallocs */
+      (GInstanceInitFunc) ags_scrolled_wave_edit_box_init,
+    };
+
+    ags_type_scrolled_wave_edit_box = g_type_register_static(GTK_TYPE_BIN,
+							     "AgsScrolledWaveEditBox", &ags_scrolled_wave_edit_box_info,
+							     0);
+  }
+  
+  return(ags_type_scrolled_wave_edit_box);
+}
+
+void
+ags_scrolled_wave_edit_box_class_init(AgsScrolledWaveEditBoxClass *scrolled_wave_edit_box)
+{
+  GObjectClass *gobject;
+  GtkWidgetClass *widget;
+
+  GParamSpec *param_spec;
+
+  ags_scrolled_wave_edit_box_parent_class = g_type_class_peek_parent(scrolled_wave_edit_box);
+
+  /* GObjectClass */
+  gobject = (GObjectClass *) scrolled_wave_edit_box;
+
+  gobject->set_property = ags_scrolled_wave_edit_box_set_property;
+  gobject->get_property = ags_scrolled_wave_edit_box_get_property;
+
+  gobject->finalize = ags_scrolled_wave_edit_box_finalize;
+
+  /* properties */  
+  /**
+   * AgsScrolledWaveEditBox:margin-top:
+   *
+   * The margin top.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_uint("margin-top",
+				 "margin top",
+				 "The margin top",
+				 0,
+				 G_MAXUINT32,
+				 0,
+				 G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_MARGIN_TOP,
+				  param_spec);
+
+  /**
+   * AgsScrolledWaveEditBox:margin-bottom:
+   *
+   * The margin bottom.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_uint("margin-bottom",
+				 "margin bottom",
+				 "The margin bottom",
+				 0,
+				 G_MAXUINT32,
+				 0,
+				 G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_MARGIN_BOTTOM,
+				  param_spec);
+
+  /**
+   * AgsScrolledWaveEditBox:margin-left:
+   *
+   * The margin left.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_uint("margin-left",
+				 "margin left",
+				 "The margin left",
+				 0,
+				 G_MAXUINT32,
+				 0,
+				 G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_MARGIN_LEFT,
+				  param_spec);
+
+  /**
+   * AgsScrolledWaveEditBox:margin-right:
+   *
+   * The margin right.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_uint("margin-right",
+				 "margin right",
+				 "The margin right",
+				 0,
+				 G_MAXUINT32,
+				 0,
+				 G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_MARGIN_RIGHT,
+				  param_spec);
+
+  /* GtkWidgetClass */
+  widget = (GtkWidgetClass *) scrolled_wave_edit_box;
+
+  widget->size_request = ags_scrolled_wave_edit_box_size_request;
+  widget->size_allocate = ags_scrolled_wave_edit_box_size_allocate;
+}
+
+void
+ags_scrolled_wave_edit_box_init(AgsScrolledWaveEditBox *scrolled_wave_edit_box)
+{
+  scrolled_wave_edit_box->margin_top = 0;
+  scrolled_wave_edit_box->margin_bottom = 0;
+  scrolled_wave_edit_box->margin_left = 0;
+  scrolled_wave_edit_box->margin_right = 0;
+
+  /* viewport */
+  scrolled_wave_edit_box->viewport = gtk_viewport_new(NULL,
+						      NULL);
+  g_object_set(scrolled_wave_edit_box->viewport,
+	       "shadow-type", GTK_SHADOW_NONE,
+	       NULL);
+  gtk_container_add(scrolled_wave_edit_box,
+		    scrolled_wave_edit_box->viewport);
+
+  /* wave_edit box */
+  scrolled_wave_edit_box->wave_edit_box = NULL;
+  
+#if 0
+  scrolled_wave_edit_box->wave_edit_box = ags_vwave_edit_box_new();
+  gtk_container_add(scrolled_wave_edit_box->viewport,
+		    scrolled_wave_edit_box->wave_edit_box);
+#endif
+}
+
+void
+ags_scrolled_wave_edit_box_set_property(GObject *gobject,
+					guint prop_id,
+					const GValue *value,
+					GParamSpec *param_spec)
+{
+  AgsScrolledWaveEditBox *scrolled_wave_edit_box;
+
+  scrolled_wave_edit_box = AGS_SCROLLED_WAVE_EDIT_BOX(gobject);
+
+  switch(prop_id){
+  case PROP_MARGIN_TOP:
+    {
+      scrolled_wave_edit_box->margin_top = g_value_get_uint(value);
+    }
+    break;
+  case PROP_MARGIN_BOTTOM:
+    {
+      scrolled_wave_edit_box->margin_bottom = g_value_get_uint(value);
+    }
+    break;
+  case PROP_MARGIN_LEFT:
+    {
+      scrolled_wave_edit_box->margin_left = g_value_get_uint(value);
+    }
+    break;
+  case PROP_MARGIN_RIGHT:
+    {
+      scrolled_wave_edit_box->margin_right = g_value_get_uint(value);
+    }
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
+    break;
+  }
+}
+
+void
+ags_scrolled_wave_edit_box_get_property(GObject *gobject,
+					guint prop_id,
+					GValue *value,
+					GParamSpec *param_spec)
+{
+  AgsScrolledWaveEditBox *scrolled_wave_edit_box;
+
+  scrolled_wave_edit_box = AGS_SCROLLED_WAVE_EDIT_BOX(gobject);
+
+  switch(prop_id){
+  case PROP_MARGIN_TOP:
+    {
+      g_value_set_uint(value,
+		       scrolled_wave_edit_box->margin_top);
+    }
+    break;
+  case PROP_MARGIN_BOTTOM:
+    {
+      g_value_set_uint(value,
+		       scrolled_wave_edit_box->margin_bottom);
+    }
+    break;
+  case PROP_MARGIN_LEFT:
+    {
+      g_value_set_uint(value,
+		       scrolled_wave_edit_box->margin_left);
+    }
+    break;
+  case PROP_MARGIN_RIGHT:
+    {
+      g_value_set_uint(value,
+		       scrolled_wave_edit_box->margin_right);
+    }
+    break;  
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
+    break;
+  }
+}
+
+void
+ags_scrolled_wave_edit_box_finalize(GObject *gobject)
+{
+  AgsScrolledWaveEditBox *scrolled_wave_edit_box;
+  
+  scrolled_wave_edit_box = AGS_SCROLLED_WAVE_EDIT_BOX(gobject);
+  
+  /* call parent */
+  G_OBJECT_CLASS(ags_scrolled_wave_edit_box_parent_class)->finalize(gobject);
+}
+
+void
+ags_scrolled_wave_edit_box_size_allocate(GtkWidget *widget,
+					 GtkAllocation *allocation)
+{
+  AgsScrolledWaveEditBox *scrolled_wave_edit_box;
+
+  GtkAllocation child_allocation;
+  GtkRequisition child_requisition;
+  
+  scrolled_wave_edit_box = AGS_SCROLLED_WAVE_EDIT_BOX(widget);
+
+  widget->allocation = *allocation;
+
+  widget->allocation.height = AGS_LEVEL_DEFAULT_HEIGHT;
+  
+  /* viewport allocation */
+  gtk_widget_get_child_requisition((GtkWidget *) scrolled_wave_edit_box->viewport,
+				   &child_requisition);
+
+  child_allocation.x = allocation->x;
+  child_allocation.y = allocation->y;
+
+  child_allocation.width = allocation->width;
+  child_allocation.height = allocation->height;
+
+  gtk_widget_size_allocate((GtkWidget *) scrolled_wave_edit_box->viewport,
+			   &child_allocation);
+
+  /* box */
+  gtk_widget_get_child_requisition((GtkWidget *) scrolled_wave_edit_box->wave_edit_box,
+				   &child_requisition);
+
+  child_allocation.x = 0;
+  child_allocation.y = 0;
+
+  child_allocation.width = allocation->width;
+  child_allocation.height = child_requisition.height;
+  
+  gtk_widget_size_allocate((GtkWidget *) scrolled_wave_edit_box->wave_edit_box,
+			   &child_allocation);
+}
+
+void
+ags_scrolled_wave_edit_box_size_request(GtkWidget *widget,
+					GtkRequisition *requisition)
+{
+  GtkRequisition child_requisition;
+
+  GtkOrientation orientation;
+
+  requisition->width = AGS_LEVEL_DEFAULT_HEIGHT;
+  requisition->height = AGS_LEVEL_DEFAULT_HEIGHT;
+  
+  gtk_widget_size_request(gtk_bin_get_child((GtkContainer *) widget),
+			  &child_requisition);
+}
+
+/**
+ * ags_scrolled_wave_edit_box_new:
+ *
+ * Create a new #AgsScrolledWaveEditBox.
+ *
+ * Returns: a new #AgsScrolledWaveEditBox
+ *
+ * Since: 1.4.0
+ */
+AgsScrolledWaveEditBox*
+ags_scrolled_wave_edit_box_new()
+{
+  AgsScrolledWaveEditBox *scrolled_wave_edit_box;
+
+  scrolled_wave_edit_box = (AgsScrolledWaveEditBox *) g_object_new(AGS_TYPE_SCROLLED_WAVE_EDIT_BOX,
+								   NULL);
+
+  return(scrolled_wave_edit_box);
+}
diff --git a/ags/X/editor/ags_scrolled_wave_edit_box.h b/ags/X/editor/ags_scrolled_wave_edit_box.h
new file mode 100644
index 0000000..0636e56
--- /dev/null
+++ b/ags/X/editor/ags_scrolled_wave_edit_box.h
@@ -0,0 +1,63 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2017 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_SCROLLED_WAVE_EDIT_BOX_H__
+#define __AGS_SCROLLED_WAVE_EDIT_BOX_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+#include <ags/X/editor/ags_wave_edit_box.h>
+
+#define AGS_TYPE_SCROLLED_WAVE_EDIT_BOX                (ags_scrolled_wave_edit_box_get_type())
+#define AGS_SCROLLED_WAVE_EDIT_BOX(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_SCROLLED_WAVE_EDIT_BOX, AgsScrolledWaveEditBox))
+#define AGS_SCROLLED_WAVE_EDIT_BOX_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_SCROLLED_WAVE_EDIT_BOX, AgsScrolledWaveEditBoxClass))
+#define AGS_IS_SCROLLED_WAVE_EDIT_BOX(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AGS_TYPE_SCROLLED_WAVE_EDIT_BOX))
+#define AGS_IS_SCROLLED_WAVE_EDIT_BOX_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_SCROLLED_WAVE_EDIT_BOX))
+#define AGS_SCROLLED_WAVE_EDIT_BOX_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS (obj, AGS_TYPE_SCROLLED_WAVE_EDIT_BOX, AgsScrolledWaveEditBoxClass))
+
+typedef struct _AgsScrolledWaveEditBox AgsScrolledWaveEditBox;
+typedef struct _AgsScrolledWaveEditBoxClass AgsScrolledWaveEditBoxClass;
+
+struct _AgsScrolledWaveEditBox
+{
+  GtkBin bin;
+
+  guint margin_top;
+  guint margin_bottom;
+  guint margin_left;
+  guint margin_right;
+  
+  GtkViewport *viewport;
+
+  AgsWaveEditBox *wave_edit_box;
+};
+
+struct _AgsScrolledWaveEditBoxClass
+{
+  GtkBinClass bin;
+};
+
+GType ags_scrolled_wave_edit_box_get_type(void);
+
+AgsScrolledWaveEditBox* ags_scrolled_wave_edit_box_new();
+
+#endif /*__AGS_SCROLLED_WAVE_EDIT_BOX_H__*/
diff --git a/ags/X/editor/ags_vautomation_edit_box.c b/ags/X/editor/ags_vautomation_edit_box.c
index 7b801ad..0d028b1 100644
--- a/ags/X/editor/ags_vautomation_edit_box.c
+++ b/ags/X/editor/ags_vautomation_edit_box.c
@@ -29,7 +29,7 @@ void ags_vautomation_edit_box_init(AgsVAutomationEditBox *vautomation_edit_box);
  * @section_id:
  * @include: ags/widget/ags_vautomation_edit_box.h
  *
- * The #AgsVAutomationEditBox is an horizontal box widget containing #AgsScale.
+ * The #AgsVAutomationEditBox is an horizontal box widget containing #AgsAutomationEdit.
  */
 
 GType
diff --git a/ags/X/editor/ags_vwave_edit_box.c b/ags/X/editor/ags_vwave_edit_box.c
new file mode 100644
index 0000000..7e5b811
--- /dev/null
+++ b/ags/X/editor/ags_vwave_edit_box.c
@@ -0,0 +1,91 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2017 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/X/editor/ags_vwave_edit_box.h>
+
+void ags_vwave_edit_box_class_init(AgsVWaveEditBoxClass *vwave_edit_box);
+void ags_vwave_edit_box_init(AgsVWaveEditBox *vwave_edit_box);
+
+/**
+ * SECTION:ags_vwave_edit_box
+ * @short_description: horizontal box widget
+ * @title: AgsVWaveEditBox
+ * @section_id:
+ * @include: ags/widget/ags_vwave_edit_box.h
+ *
+ * The #AgsVWaveEditBox is an horizontal box widget containing #AgsWaveEdit.
+ */
+
+GType
+ags_vwave_edit_box_get_type(void)
+{
+  static GType ags_type_vwave_edit_box = 0;
+
+  if(!ags_type_vwave_edit_box){
+    static const GTypeInfo ags_vwave_edit_box_info = {
+      sizeof (AgsVWaveEditBoxClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      (GClassInitFunc) ags_vwave_edit_box_class_init,
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof (AgsVWaveEditBox),
+      0,    /* n_preallocs */
+      (GInstanceInitFunc) ags_vwave_edit_box_init,
+    };
+
+    ags_type_vwave_edit_box = g_type_register_static(AGS_TYPE_WAVE_EDIT_BOX,
+						     "AgsVWaveEditBox", &ags_vwave_edit_box_info,
+						     0);
+  }
+  
+  return(ags_type_vwave_edit_box);
+}
+
+void
+ags_vwave_edit_box_class_init(AgsVWaveEditBoxClass *vwave_edit_box)
+{
+}
+
+void
+ags_vwave_edit_box_init(AgsVWaveEditBox *vwave_edit_box)
+{
+  gtk_orientable_set_orientation(GTK_ORIENTABLE(vwave_edit_box),
+				 GTK_ORIENTATION_VERTICAL);
+}
+
+/**
+ * ags_vwave_edit_box_new:
+ * 
+ * Create a new instance of #AgsVWaveEditBox.
+ * 
+ * Returns: the new #AgsVWaveEditBox instance
+ * 
+ * Since: 1.4.0
+ */
+AgsVWaveEditBox*
+ags_vwave_edit_box_new()
+{
+  AgsVWaveEditBox *vwave_edit_box;
+
+  vwave_edit_box = (AgsVWaveEditBox *) g_object_new(AGS_TYPE_VWAVE_EDIT_BOX,
+						    NULL);
+  
+  return(vwave_edit_box);
+}
diff --git a/ags/X/editor/ags_vwave_edit_box.h b/ags/X/editor/ags_vwave_edit_box.h
new file mode 100644
index 0000000..24bc186
--- /dev/null
+++ b/ags/X/editor/ags_vwave_edit_box.h
@@ -0,0 +1,54 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2017 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_VWAVE_EDIT_BOX_H__
+#define __AGS_VWAVE_EDIT_BOX_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+#include <ags/X/editor/ags_wave_edit_box.h>
+
+#define AGS_TYPE_VWAVE_EDIT_BOX                (ags_vwave_edit_box_get_type())
+#define AGS_VWAVE_EDIT_BOX(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_VWAVE_EDIT_BOX, AgsVWaveEditBox))
+#define AGS_VWAVE_EDIT_BOX_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_VWAVE_EDIT_BOX, AgsVWaveEditBoxClass))
+#define AGS_IS_VWAVE_EDIT_BOX(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AGS_TYPE_VWAVE_EDIT_BOX))
+#define AGS_IS_VWAVE_EDIT_BOX_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_VWAVE_EDIT_BOX))
+#define AGS_VWAVE_EDIT_BOX_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS (obj, AGS_TYPE_VWAVE_EDIT_BOX, AgsVWaveEditBoxClass))
+
+typedef struct _AgsVWaveEditBox AgsVWaveEditBox;
+typedef struct _AgsVWaveEditBoxClass AgsVWaveEditBoxClass;
+
+struct _AgsVWaveEditBox
+{
+  AgsWaveEditBox wave_edit_box;
+};
+
+struct _AgsVWaveEditBoxClass
+{
+  AgsWaveEditBoxClass wave_edit_box;
+};
+
+GType ags_vwave_edit_box_get_type(void);
+
+AgsVWaveEditBox* ags_vwave_edit_box_new();
+
+#endif /*__AGS_VWAVE_EDIT_BOX_H__*/
diff --git a/ags/X/editor/ags_wave_edit.c b/ags/X/editor/ags_wave_edit.c
index b065e08..44b193c 100644
--- a/ags/X/editor/ags_wave_edit.c
+++ b/ags/X/editor/ags_wave_edit.c
@@ -59,6 +59,8 @@ gboolean ags_accessible_wave_edit_set_description(AtkAction *action,
 gchar* ags_accessible_wave_edit_get_localized_name(AtkAction *action,
 						   gint i);
 
+gboolean ags_wave_edit_auto_scroll_timeout(GtkWidget *widget);
+
 /**
  * SECTION:ags_wave_edit
  * @short_description: edit audio data
@@ -71,9 +73,11 @@ gchar* ags_accessible_wave_edit_get_localized_name(AtkAction *action,
 
 static gpointer ags_wave_edit_parent_class = NULL;
 
+static GQuark quark_accessible_object = 0;
+
 GtkStyle *wave_edit_style = NULL;
 
-static GQuark quark_accessible_object = 0;
+GHashTable *ags_wave_edit_auto_scroll = NULL;
 
 GType
 ags_wave_edit_get_type(void)
@@ -188,26 +192,40 @@ ags_wave_edit_init(AgsWaveEdit *wave_edit)
 {
   GtkAdjustment *adjustment;
 
+  g_object_set(wave_edit,
+	       "can-focus", FALSE,
+	       "n-columns", 3,
+	       "n-rows", 4,
+	       "homogeneous", FALSE,
+	       NULL);
+
   wave_edit->flags = 0;
+  wave_edit->mode = AGS_WAVE_EDIT_NO_EDIT_MODE;
 
   wave_edit->key_mask = 0;
+  
+  wave_edit->note_offset = 0;
+  wave_edit->note_offset_absolute = 0;
 
-  wave_edit->map_width = AGS_WAVE_EDIT_MAX_CONTROLS;
-  wave_edit->map_height = 0;
-
-  wave_edit->edit_x = 0;
-  wave_edit->edit_y = 0;
+  wave_edit->control_width = AGS_WAVE_EDIT_DEFAULT_CONTROL_WIDTH;
+  wave_edit->control_height = AGS_WAVE_EDIT_DEFAULT_CONTROL_HEIGHT;
   
-  wave_edit->select_x0 = 0;
-  wave_edit->select_x1 = 0;
-  wave_edit->select_y0 = 0;
-  wave_edit->select_y1 = 0;
+  wave_edit->cursor_position_x = AGS_WAVE_EDIT_DEFAULT_CURSOR_POSITION_X;
+  wave_edit->cursor_position_y = AGS_WAVE_EDIT_DEFAULT_CURSOR_POSITION_Y;
+
+  wave_edit->selection_x0 = 0;
+  wave_edit->selection_x1 = 0;
+  wave_edit->selection_y0 = 0;
+  wave_edit->selection_y1 = 0;
 
   if(wave_edit_style == NULL){
     wave_edit_style = gtk_style_copy(gtk_widget_get_style(wave_edit));
   }
 
   wave_edit->ruler = ags_ruler_new();
+  g_object_set(wave_edit->ruler,
+	       "no-show-all", TRUE,
+	       NULL);
   gtk_table_attach(GTK_TABLE(wave_edit),
 		   (GtkWidget *) wave_edit->ruler,
 		   0, 1,
@@ -216,9 +234,12 @@ ags_wave_edit_init(AgsWaveEdit *wave_edit)
 		   GTK_FILL,
 		   0, 0);
 
+  wave_edit->lower = AGS_WAVE_EDIT_DEFAULT_LOWER;
+  wave_edit->upper = AGS_WAVE_EDIT_DEFAULT_UPPER;
+
+  wave_edit->default_value = AGS_WAVE_EDIT_DEFAULT_VALUE;
+
   wave_edit->drawing_area = (GtkDrawingArea *) gtk_drawing_area_new();
-  gtk_widget_set_style((GtkWidget *) wave_edit->drawing_area,
-		       wave_edit_style);
   gtk_widget_set_events(GTK_WIDGET (wave_edit->drawing_area), GDK_EXPOSURE_MASK
 			| GDK_LEAVE_NOTIFY_MASK
 			| GDK_BUTTON_PRESS_MASK
@@ -231,6 +252,8 @@ ags_wave_edit_init(AgsWaveEdit *wave_edit)
   gtk_widget_set_can_focus((GtkWidget *) wave_edit->drawing_area,
 			   TRUE);
     
+  gtk_widget_set_size_request(wave_edit->drawing_area,
+			      -1, AGS_LEVEL_DEFAULT_HEIGHT);
   gtk_table_attach(GTK_TABLE(wave_edit),
 		   (GtkWidget *) wave_edit->drawing_area,
 		   0, 1,
@@ -239,9 +262,14 @@ ags_wave_edit_init(AgsWaveEdit *wave_edit)
 		   GTK_FILL|GTK_EXPAND,
 		   0, 0);
     
-  /* GtkScrollbars */
-  adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 1.0, 1.0, 1.0);
-  wave_edit->vscrollbar = (GtkVScrollbar *) gtk_vscrollbar_new(adjustment);
+  /* vscrollbar */
+  adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 1.0, wave_edit->control_height, 1.0);
+  wave_edit->vscrollbar = gtk_vscrollbar_new(adjustment);
+  g_object_set(wave_edit->vscrollbar,
+	       "no-show-all", TRUE,
+	       NULL);
+  gtk_widget_set_size_request(wave_edit->vscrollbar,
+			      -1, AGS_LEVEL_DEFAULT_HEIGHT);
   gtk_table_attach(GTK_TABLE(wave_edit),
 		   (GtkWidget *) wave_edit->vscrollbar,
 		   1, 2,
@@ -249,14 +277,31 @@ ags_wave_edit_init(AgsWaveEdit *wave_edit)
 		   GTK_FILL, GTK_FILL,
 		   0, 0);
 
-  adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 1.0, (gdouble) AGS_WAVE_EDIT_DEFAULT_WIDTH, 1.0);
-  wave_edit->hscrollbar = (GtkHScrollbar *) gtk_hscrollbar_new(adjustment);
+  /* hscrollbar */
+  adjustment = (GtkAdjustment *) gtk_adjustment_new(0.0, 0.0, 1.0, 1.0, (gdouble) wave_edit->control_width, 1.0);
+  wave_edit->hscrollbar = gtk_hscrollbar_new(adjustment);
+  g_object_set(wave_edit->hscrollbar,
+	       "no-show-all", TRUE,
+	       NULL);
+  gtk_widget_set_size_request(wave_edit->hscrollbar,
+			      -1, -1);
   gtk_table_attach(GTK_TABLE(wave_edit),
 		   (GtkWidget *) wave_edit->hscrollbar,
 		   0, 1,
 		   2, 3,
 		   GTK_FILL, GTK_FILL,
 		   0, 0);
+
+  /* auto-scroll */
+  if(ags_wave_edit_auto_scroll == NULL){
+    ags_wave_edit_auto_scroll = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+						      NULL,
+						      NULL);
+  }
+
+  g_hash_table_insert(ags_wave_edit_auto_scroll,
+		      wave_edit, ags_wave_edit_auto_scroll_timeout);
+  g_timeout_add(1000 / 30, (GSourceFunc) ags_wave_edit_auto_scroll_timeout, (gpointer) wave_edit);
 }
 
 void
@@ -654,6 +699,52 @@ ags_accessible_wave_edit_get_localized_name(AtkAction *action,
   return(NULL);
 }
 
+gboolean
+ags_wave_edit_auto_scroll_timeout(GtkWidget *widget)
+{
+  if(g_hash_table_lookup(ags_wave_edit_auto_scroll,
+			 widget) != NULL){
+    AgsWaveEditor *wave_editor;
+    AgsWaveEdit *wave_edit;
+    AgsWaveToolbar *wave_toolbar;
+
+    double zoom;
+    double x;
+    
+    wave_edit = AGS_WAVE_EDIT(widget);
+
+    if((AGS_WAVE_EDIT_AUTO_SCROLL & (wave_edit->flags)) == 0){
+      return(TRUE);
+    }
+    
+    wave_editor = gtk_widget_get_ancestor(wave_edit,
+					  AGS_TYPE_WAVE_EDITOR);
+    
+    if(wave_editor->selected_machine == NULL){
+      return(TRUE);
+    }
+
+    wave_toolbar = wave_editor->wave_toolbar;
+
+    /* zoom */
+    zoom = exp2((double) gtk_combo_box_get_active((GtkComboBox *) wave_toolbar->zoom) - 2.0);
+
+    /* reset offset */
+    wave_edit->note_offset = ags_soundcard_get_note_offset(AGS_SOUNDCARD(wave_editor->selected_machine->audio->soundcard));
+    wave_edit->note_offset_absolute = ags_soundcard_get_note_offset_absolute(AGS_SOUNDCARD(wave_editor->selected_machine->audio->soundcard));
+
+    /* reset scrollbar */
+    x = ((wave_edit->note_offset * wave_edit->control_width) / (AGS_WAVE_EDITOR_MAX_CONTROLS * wave_edit->control_width)) * GTK_RANGE(wave_edit->hscrollbar)->adjustment->upper;
+    
+    gtk_range_set_value(GTK_RANGE(wave_edit->hscrollbar),
+			x);
+
+    return(TRUE);
+  }else{
+    return(FALSE);
+  }
+}
+
 /**
  * ags_wave_edit_new:
  *
diff --git a/ags/X/editor/ags_wave_edit.h b/ags/X/editor/ags_wave_edit.h
index bb0b12c..7dfab27 100644
--- a/ags/X/editor/ags_wave_edit.h
+++ b/ags/X/editor/ags_wave_edit.h
@@ -25,9 +25,9 @@
 
 #include <gtk/gtk.h>
 
-#include <ags/widget/ags_ruler.h>
-
-#include <ags/X/editor/ags_level.h>
+#include <ags/libags.h>
+#include <ags/libags-audio.h>
+#include <ags/libags-gui.h>
 
 #define AGS_TYPE_WAVE_EDIT                (ags_wave_edit_get_type())
 #define AGS_WAVE_EDIT(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_WAVE_EDIT, AgsWaveEdit))
@@ -36,27 +36,49 @@
 #define AGS_IS_WAVE_EDIT_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_WAVE_EDIT))
 #define AGS_WAVE_EDIT_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS (obj, AGS_TYPE_WAVE_EDIT, AgsWaveEditClass))
 
-#define AGS_WAVE_EDIT_MAX_CONTROLS (16 * 64 * 1200)
-#define AGS_WAVE_EDIT_DEFAULT_MARGIN (8)
-#define AGS_WAVE_EDIT_DEFAULT_WIDTH (64)
+#define AGS_WAVE_EDIT_DEFAULT_HEIGHT (512)
+#define AGS_WAVE_EDIT_DEFAULT_WIDTH (512)
+
+#define AGS_WAVE_EDIT_DEFAULT_CONTROL_WIDTH (64)
+#define AGS_WAVE_EDIT_DEFAULT_CONTROL_HEIGHT (8)
+
+#define AGS_WAVE_EDIT_DEFAULT_STEP_COUNT (16)
+
+#define AGS_WAVE_EDIT_DEFAULT_CURSOR_POSITION_X (0)
+#define AGS_WAVE_EDIT_DEFAULT_CURSOR_POSITION_Y (0.0)
+
+#define AGS_WAVE_EDIT_DEFAULT_FADER_WIDTH (3)
+
+#define AGS_WAVE_EDIT_CURSOR_WIDTH (5)
+#define AGS_WAVE_EDIT_CURSOR_HEIGHT (5)
+
+#define AGS_WAVE_EDIT_MIN_ZOOM (1.0 / 16.0)
+#define AGS_WAVE_EDIT_MAX_ZOOM (4.0)
+
+#define AGS_WAVE_EDIT_DEFAULT_LOWER (0.0)
+#define AGS_WAVE_EDIT_DEFAULT_UPPER (1.0)
+#define AGS_WAVE_EDIT_DEFAULT_VALUE (0.0)
+
+#define AGS_WAVE_EDIT_DEFAULT_PADDING (8)
 
 typedef struct _AgsWaveEdit AgsWaveEdit;
 typedef struct _AgsWaveEditClass AgsWaveEditClass;
 
 typedef enum{
   AGS_WAVE_EDIT_CONNECTED                   = 1,
-  AGS_WAVE_EDIT_RESETING_VERTICALLY         = 1 <<  1,
-  AGS_WAVE_EDIT_RESETING_HORIZONTALLY       = 1 <<  2,
-  AGS_WAVE_EDIT_POSITION_CURSOR             = 1 <<  3,
-  AGS_WAVE_EDIT_SELECTING_AUDIO_DATA        = 1 <<  4,
+  AGS_WAVE_EDIT_AUTO_SCROLL                 = 1 <<  1,
+  AGS_WAVE_EDIT_SHOW_RULER                  = 1 <<  2,
+  AGS_WAVE_EDIT_SHOW_VSCROLLBAR             = 1 <<  3,
+  AGS_WAVE_EDIT_SHOW_HSCROLLBAR             = 1 <<  4,
 }AgsWaveEditFlags;
 
 typedef enum{
-  AGS_WAVE_EDIT_RESET_VSCROLLBAR   = 1,
-  AGS_WAVE_EDIT_RESET_HSCROLLBAR   = 1 <<  1,
-  AGS_WAVE_EDIT_RESET_WIDTH        = 1 <<  2,
-  AGS_WAVE_EDIT_RESET_HEIGHT       = 1 <<  3, // reserved
-}AgsWaveEditResetFlags;
+  AGS_WAVE_EDIT_NO_EDIT_MODE,
+  AGS_WAVE_EDIT_POSITION_CURSOR,
+  AGS_WAVE_EDIT_ADD_ACCELERATION,
+  AGS_WAVE_EDIT_DELETE_ACCELERATION,
+  AGS_WAVE_EDIT_SELECT_ACCELERATION,
+}AgsWaveEditMode;
 
 typedef enum{
   AGS_WAVE_EDIT_KEY_L_CONTROL       = 1,
@@ -70,22 +92,32 @@ struct _AgsWaveEdit
   GtkTable table;
 
   guint flags;
+  guint mode;
 
   guint key_mask;
   
-  guint map_width;
-  guint map_height;
+  guint note_offset;
+  guint note_offset_absolute;
 
-  guint edit_x;
-  guint edit_y;
-  
-  guint select_x0;
-  guint select_y0;
-  guint select_x1;
-  guint select_y1;
+  guint control_width;
+  guint control_height;
+
+  guint step_count;
+
+  guint cursor_position_x;
+  gdouble cursor_position_y;
+
+  guint selection_x0;
+  guint selection_x1;
+  guint selection_y0;
+  guint selection_y1;
   
   AgsRuler *ruler;
 
+  gdouble lower;
+  gdouble upper;
+  gdouble default_value;
+
   GtkDrawingArea *drawing_area;
   
   GtkVScrollbar *vscrollbar;
diff --git a/ags/X/editor/ags_wave_edit_box.c b/ags/X/editor/ags_wave_edit_box.c
new file mode 100644
index 0000000..cb7e0b8
--- /dev/null
+++ b/ags/X/editor/ags_wave_edit_box.c
@@ -0,0 +1,217 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2017 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/X/editor/ags_wave_edit_box.h>
+
+#include <ags/X/editor/ags_wave_edit.h>
+
+void ags_wave_edit_box_class_init(AgsWaveEditBoxClass *wave_edit_box);
+void ags_wave_edit_box_init(AgsWaveEditBox *wave_edit_box);
+void ags_wave_edit_box_set_property(GObject *gobject,
+				    guint prop_id,
+				    const GValue *value,
+				    GParamSpec *param_spec);
+void ags_wave_edit_box_get_property(GObject *gobject,
+				    guint prop_id,
+				    GValue *value,
+				    GParamSpec *param_spec);
+void ags_wave_edit_box_finalize(GObject *gobject);
+
+GType ags_wave_edit_box_child_type(GtkContainer *container);
+
+/**
+ * SECTION:ags_wave_edit_box
+ * @short_description: abstract box widget
+ * @title: AgsWaveEditBox
+ * @section_id:
+ * @include: ags/widget/ags_wave_edit_box.h
+ *
+ * The #AgsWaveEditBox is an abstract box widget containing #AgsWaveEdit.
+ */
+
+enum{
+  PROP_0,
+  PROP_FIXED_EDIT_WIDTH,
+  PROP_FIXED_EDIT_HEIGHT,
+};
+
+static gpointer ags_wave_edit_box_parent_class = NULL;
+
+GType
+ags_wave_edit_box_get_type(void)
+{
+  static GType ags_type_wave_edit_box = 0;
+
+  if(!ags_type_wave_edit_box){
+    static const GTypeInfo ags_wave_edit_box_info = {
+      sizeof (AgsWaveEditBoxClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      (GClassInitFunc) ags_wave_edit_box_class_init,
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof (AgsWaveEditBox),
+      0,    /* n_preallocs */
+      (GInstanceInitFunc) ags_wave_edit_box_init,
+    };
+
+    ags_type_wave_edit_box = g_type_register_static(GTK_TYPE_BOX,
+						    "AgsWaveEditBox", &ags_wave_edit_box_info,
+						    0);
+  }
+  
+  return(ags_type_wave_edit_box);
+}
+
+void
+ags_wave_edit_box_class_init(AgsWaveEditBoxClass *wave_edit_box)
+{
+  GObjectClass *gobject;
+  GtkWidgetClass *widget;
+  GtkContainerClass *container;
+
+  GParamSpec *param_spec;
+
+  ags_wave_edit_box_parent_class = g_type_class_peek_parent(wave_edit_box);
+
+  /* GObjectClass */
+  gobject = (GObjectClass *) wave_edit_box;
+
+  gobject->set_property = ags_wave_edit_box_set_property;
+  gobject->get_property = ags_wave_edit_box_get_property;
+
+  gobject->finalize = ags_wave_edit_box_finalize;
+
+  /* properties */
+  /**
+   * AgsWaveEditBox:fixed-edit-height:
+   *
+   * The fixed height of a edit.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_uint("fixed-edit-height",
+				 "fixed edit height",
+				 "The fixed height of a edit",
+				 0,
+				 G_MAXUINT,
+				 AGS_WAVE_EDIT_BOX_DEFAULT_FIXED_EDIT_HEIGHT,
+				 G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_FIXED_EDIT_HEIGHT,
+				  param_spec);
+
+  /* GtkWidgetClass */
+  widget = (GtkWidgetClass *) wave_edit_box;
+  
+  /* GtkContainerClass */
+  container = (GtkWidgetClass *) wave_edit_box;
+
+  container->child_type = ags_wave_edit_box_child_type;
+}
+
+void
+ags_wave_edit_box_init(AgsWaveEditBox *wave_edit_box)
+{
+  g_object_set(wave_edit_box,
+	       "homogeneous", FALSE,
+	       "spacing", 0,
+	       NULL);
+  
+  wave_edit_box->flags = 0;
+
+  wave_edit_box->fixed_edit_height = AGS_WAVE_EDIT_BOX_DEFAULT_FIXED_EDIT_HEIGHT;
+}
+
+void
+ags_wave_edit_box_set_property(GObject *gobject,
+			       guint prop_id,
+			       const GValue *value,
+			       GParamSpec *param_spec)
+{
+  AgsWaveEditBox *wave_edit_box;
+
+  wave_edit_box = AGS_WAVE_EDIT_BOX(gobject);
+
+  switch(prop_id){
+  case PROP_FIXED_EDIT_HEIGHT:
+    {
+      wave_edit_box->fixed_edit_height = g_value_get_uint(value);
+    }
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
+    break;
+  }
+}
+
+void
+ags_wave_edit_box_get_property(GObject *gobject,
+			       guint prop_id,
+			       GValue *value,
+			       GParamSpec *param_spec)
+{
+  AgsWaveEditBox *wave_edit_box;
+
+  wave_edit_box = AGS_WAVE_EDIT_BOX(gobject);
+
+  switch(prop_id){
+  case PROP_FIXED_EDIT_HEIGHT:
+    {
+      g_value_set_uint(value,
+		       wave_edit_box->fixed_edit_height);
+    }
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
+    break;
+  }
+}
+
+void
+ags_wave_edit_box_finalize(GObject *gobject)
+{
+  /* call parent */
+  G_OBJECT_CLASS(ags_wave_edit_box_parent_class)->finalize(gobject);
+}
+
+GType ags_wave_edit_box_child_type(GtkContainer *container)
+{
+  return(AGS_TYPE_WAVE_EDIT);
+}
+
+/**
+ * ags_wave_edit_box_new:
+ * 
+ * Create a new instance of #AgsWaveEditBox.
+ * 
+ * Returns: the new #AgsWaveEditBox instance
+ * 
+ * Since: 1.4.0
+ */
+AgsWaveEditBox*
+ags_wave_edit_box_new()
+{
+  AgsWaveEditBox *wave_edit_box;
+
+  wave_edit_box = (AgsWaveEditBox *) g_object_new(AGS_TYPE_WAVE_EDIT_BOX,
+						  NULL);
+  
+  return(wave_edit_box);
+}
diff --git a/ags/X/editor/ags_wave_edit_box.h b/ags/X/editor/ags_wave_edit_box.h
new file mode 100644
index 0000000..99c674d
--- /dev/null
+++ b/ags/X/editor/ags_wave_edit_box.h
@@ -0,0 +1,62 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2017 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_WAVE_EDIT_BOX_H__
+#define __AGS_WAVE_EDIT_BOX_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+#define AGS_TYPE_WAVE_EDIT_BOX                (ags_wave_edit_box_get_type())
+#define AGS_WAVE_EDIT_BOX(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_WAVE_EDIT_BOX, AgsWaveEditBox))
+#define AGS_WAVE_EDIT_BOX_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_WAVE_EDIT_BOX, AgsWaveEditBoxClass))
+#define AGS_IS_WAVE_EDIT_BOX(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AGS_TYPE_WAVE_EDIT_BOX))
+#define AGS_IS_WAVE_EDIT_BOX_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_WAVE_EDIT_BOX))
+#define AGS_WAVE_EDIT_BOX_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS (obj, AGS_TYPE_WAVE_EDIT_BOX, AgsWaveEditBoxClass))
+
+#define AGS_WAVE_EDIT_BOX_DEFAULT_FIXED_EDIT_HEIGHT (128)
+
+typedef struct _AgsWaveEditBox AgsWaveEditBox;
+typedef struct _AgsWaveEditBoxClass AgsWaveEditBoxClass;
+
+typedef enum{
+  AGS_WAVE_EDIT_BOX_FIXED_EDIT_SIZE  = 1,
+}AgsWaveEditBoxFlags;
+
+struct _AgsWaveEditBox
+{
+  GtkBox box;
+
+  guint flags;
+
+  guint fixed_edit_height;
+};
+
+struct _AgsWaveEditBoxClass
+{
+  GtkBoxClass box;
+};
+
+GType ags_wave_edit_box_get_type(void);
+
+AgsWaveEditBox* ags_wave_edit_box_new();
+
+#endif /*__AGS_WAVE_EDIT_BOX_H__*/
diff --git a/ags/X/machine/ags_audiorec.c b/ags/X/machine/ags_audiorec.c
index 9d8f59d..04b4ce3 100644
--- a/ags/X/machine/ags_audiorec.c
+++ b/ags/X/machine/ags_audiorec.c
@@ -18,6 +18,7 @@
  */
 
 #include <ags/X/machine/ags_audiorec.h>
+#include <ags/X/machine/ags_audiorec_callbacks.h>
 
 #include <ags/libags.h>
 #include <ags/libags-audio.h>
@@ -33,6 +34,7 @@ void ags_audiorec_connect(AgsConnectable *connectable);
 void ags_audiorec_disconnect(AgsConnectable *connectable);
 void ags_audiorec_finalize(GObject *gobject);
 void ags_audiorec_show(GtkWidget *widget);
+void ags_audiorec_map_recall(AgsMachine *machine);
 gchar* ags_audiorec_get_name(AgsPlugin *plugin);
 void ags_audiorec_set_name(AgsPlugin *plugin, gchar *name);
 gchar* ags_audiorec_get_xml_type(AgsPlugin *plugin);
@@ -40,6 +42,16 @@ void ags_audiorec_set_xml_type(AgsPlugin *plugin, gchar *xml_type);
 void ags_audiorec_read(AgsFile *file, xmlNode *node, AgsPlugin *plugin);
 xmlNode* ags_audiorec_write(AgsFile *file, xmlNode *parent, AgsPlugin *plugin);
 
+void ags_audiorec_resize_audio_channels(AgsMachine *machine,
+					guint audio_channels, guint audio_channels_old,
+					gpointer data);
+void ags_audiorec_resize_pads(AgsMachine *machine, GType type,
+			      guint pads, guint pads_old,
+			      gpointer data);
+
+void ags_audiorec_output_map_recall(AgsAudiorec *audiorec, guint output_pad_start);
+void ags_audiorec_input_map_recall(AgsAudiorec *audiorec, guint input_pad_start);
+
 /**
  * SECTION:ags_audiorec
  * @short_description: record audio data
@@ -120,6 +132,8 @@ ags_audiorec_class_init(AgsAudiorecClass *audiorec)
 
   /* AgsMachineClass */
   machine = (AgsMachineClass *) audiorec;
+
+  machine->map_recall = ags_audiorec_map_recall;
 }
 
 void
@@ -146,6 +160,27 @@ ags_audiorec_plugin_interface_init(AgsPluginInterface *plugin)
 void
 ags_audiorec_init(AgsAudiorec *audiorec)
 {
+  GtkHBox *hbox;
+  GtkHBox *vbox;
+  GtkHBox *filename_hbox;
+  GtkHBox *radio_hbox;
+  GtkFrame *frame;
+  GtkLabel *label;
+
+  AgsAudio *audio;
+
+  audio = AGS_MACHINE(audiorec)->audio;
+  audio->flags |= (AGS_AUDIO_SYNC |
+		   AGS_AUDIO_OUTPUT_HAS_RECYCLING |
+		   AGS_AUDIO_INPUT_HAS_RECYCLING);
+
+  /* audio resize */
+  g_signal_connect_after(G_OBJECT(audiorec), "resize-audio-channels",
+			 G_CALLBACK(ags_audiorec_resize_audio_channels), NULL);
+
+  g_signal_connect_after(G_OBJECT(audiorec), "resize-pads",
+			 G_CALLBACK(ags_audiorec_resize_pads), NULL);
+  
   /* mapped IO */
   audiorec->mapped_input_pad = 0;
   audiorec->mapped_output_pad = 0;
@@ -153,6 +188,100 @@ ags_audiorec_init(AgsAudiorec *audiorec)
   /* name and xml type */
   audiorec->name = NULL;
   audiorec->xml_type = "ags-audiorec";
+
+  /* context menu */
+  ags_machine_popup_add_connection_options((AgsMachine *) audiorec,
+					   (AGS_MACHINE_POPUP_CONNECTION_EDITOR));
+
+  AGS_MACHINE(audiorec)->connection_flags |= AGS_MACHINE_SHOW_AUDIO_INPUT_CONNECTION;
+  
+  /* hbox */
+  hbox = (GtkHBox *) gtk_hbox_new(FALSE,
+				  0);
+  gtk_container_add((GtkContainer *) (gtk_bin_get_child((GtkBin *) audiorec)),
+		    (GtkWidget *) hbox);
+
+  /* frame - filename and open */
+  frame = (GtkFrame *) gtk_frame_new("file");
+  gtk_box_pack_start(hbox,
+		     frame,
+		     FALSE, FALSE,
+		     0);
+
+  vbox = (GtkHBox *) gtk_vbox_new(FALSE,
+				  0);
+  gtk_container_add((GtkContainer *) frame,
+		    (GtkWidget *) vbox);
+
+  /* filename */
+  filename_hbox = (GtkHBox *) gtk_hbox_new(FALSE,
+					   0);
+  gtk_box_pack_start(vbox,
+		     filename_hbox,
+		     FALSE, FALSE,
+		     0);
+  
+  label = gtk_label_new("filename: ");
+  gtk_box_pack_start(filename_hbox,
+		     label,
+		     FALSE, FALSE,
+		     0);
+
+  audiorec->filename = (GtkEntry *) gtk_entry_new();
+  gtk_box_pack_start(filename_hbox,
+		     audiorec->filename,
+		     FALSE, FALSE,
+		     0);
+
+  audiorec->open = (GtkButton *) gtk_button_new_from_stock(GTK_STOCK_OPEN);
+  gtk_box_pack_start(filename_hbox,
+		     audiorec->open,
+		     FALSE, FALSE,
+		     0);
+  
+  /* radio */
+  radio_hbox = (GtkHBox *) gtk_hbox_new(FALSE,
+					0);
+  gtk_box_pack_start(vbox,
+		     radio_hbox,
+		     FALSE, FALSE,
+		     0);
+
+  audiorec->keep_data = gtk_radio_button_new_with_label_from_widget(NULL,
+								    "keep");
+  gtk_box_pack_start(radio_hbox,
+		     audiorec->keep_data,
+		     FALSE, FALSE,
+		     0);
+
+  audiorec->replace_data = gtk_radio_button_new_with_label_from_widget(audiorec->keep_data,
+								       "replace");
+  gtk_box_pack_start(radio_hbox,
+		     audiorec->replace_data,
+		     FALSE, FALSE,
+		     0);
+  
+  audiorec->mix_data = gtk_radio_button_new_with_label_from_widget(audiorec->keep_data,
+								   "mix");
+  gtk_box_pack_start(radio_hbox,
+		     audiorec->mix_data,
+		     FALSE, FALSE,
+		     0);
+  
+  /* frame - hindicator */
+  frame = (GtkFrame *) gtk_frame_new("input");
+  gtk_box_pack_start(hbox,
+		     frame,
+		     FALSE, FALSE,
+		     0);
+
+  audiorec->hindicator_vbox = (GtkHBox *) gtk_vbox_new(FALSE,
+						       0);
+  gtk_container_add((GtkContainer *) frame,
+		    (GtkWidget *) audiorec->hindicator_vbox);
+
+  /* dialog */
+  audiorec->open_dialog = NULL;
 }
 
 void
@@ -176,6 +305,20 @@ ags_audiorec_connect(AgsConnectable *connectable)
   ags_audiorec_parent_connectable_interface->connect(connectable);
 
   audiorec = AGS_AUDIOREC(connectable);
+
+  /* filename */
+  g_signal_connect(audiorec->open, "clicked",
+		   G_CALLBACK(ags_audiorec_open_callback), audiorec);
+
+  /* mode */
+  g_signal_connect(audiorec->keep_data, "clicked",
+		   G_CALLBACK(ags_audiorec_keep_data_callback), audiorec);
+
+  g_signal_connect(audiorec->mix_data, "clicked",
+		   G_CALLBACK(ags_audiorec_mix_data_callback), audiorec);
+
+  g_signal_connect(audiorec->replace_data, "clicked",
+		   G_CALLBACK(ags_audiorec_replace_data_callback), audiorec);
 }
 
 void
@@ -192,6 +335,32 @@ ags_audiorec_disconnect(AgsConnectable *connectable)
   ags_audiorec_parent_connectable_interface->disconnect(connectable);
 
   audiorec = AGS_AUDIOREC(connectable);
+
+  /* filename */
+  g_object_disconnect(audiorec->open,
+		      "any_signal::clicked",
+		      G_CALLBACK(ags_audiorec_open_callback),
+		      audiorec,
+		      NULL);
+
+  /* mode */
+  g_object_disconnect(audiorec->keep_data,
+		      "any_signal::clicked",
+		      G_CALLBACK(ags_audiorec_keep_data_callback),
+		      audiorec,
+		      NULL);
+
+  g_object_disconnect(audiorec->replace_data,
+		      "any_signal::clicked",
+		      G_CALLBACK(ags_audiorec_replace_data_callback),
+		      audiorec,
+		      NULL);
+
+  g_object_disconnect(audiorec->mix_data,
+		      "any_signal::clicked",
+		      G_CALLBACK(ags_audiorec_mix_data_callback),
+		      audiorec,
+		      NULL);
 }
 
 void
@@ -200,6 +369,55 @@ ags_audiorec_show(GtkWidget *widget)
   GTK_WIDGET_CLASS(ags_audiorec_parent_class)->show(widget);
 }
 
+void
+ags_audiorec_map_recall(AgsMachine *machine)
+{
+  AgsAudiorec *audiorec;
+
+  AgsAudio *audio;
+
+  if((AGS_MACHINE_MAPPED_RECALL & (machine->flags)) != 0 ||
+     (AGS_MACHINE_PREMAPPED_RECALL & (machine->flags)) != 0){
+    return;
+  }
+
+  audiorec = AGS_AUDIOREC(machine);
+
+  audio = machine->audio;
+
+  /* ags-play-wave */
+  ags_recall_factory_create(audio,
+			    NULL, NULL,
+			    "ags-play-wave",
+			    0, 0,
+			    0, 0,
+			    (AGS_RECALL_FACTORY_INPUT |
+			     AGS_RECALL_FACTORY_ADD |
+			     AGS_RECALL_FACTORY_RECALL),
+			    0);
+
+  /* depending on destination */
+  ags_audiorec_input_map_recall(audiorec, 0);
+
+  /* depending on destination */
+  ags_audiorec_output_map_recall(audiorec, 0);
+
+  /* call parent */
+  AGS_MACHINE_CLASS(ags_audiorec_parent_class)->map_recall(machine);  
+}
+
+void
+ags_audiorec_output_map_recall(AgsAudiorec *audiorec, guint output_pad_start)
+{
+  //TODO:JK: implement me
+}
+
+void
+ags_audiorec_input_map_recall(AgsAudiorec *audiorec, guint input_pad_start)
+{
+  //TODO:JK: implement me
+}
+
 gchar*
 ags_audiorec_get_name(AgsPlugin *plugin)
 {
@@ -225,6 +443,112 @@ ags_audiorec_set_xml_type(AgsPlugin *plugin, gchar *xml_type)
 }
 
 void
+ags_audiorec_resize_audio_channels(AgsMachine *machine,
+				   guint audio_channels, guint audio_channels_old,
+				   gpointer data)
+{
+  AgsAudiorec *audiorec;
+
+  guint pads;
+  
+  audiorec = AGS_AUDIOREC(machine);
+
+  pads = machine->audio->input_pads;
+
+  if(audio_channels > audio_channels_old &&
+     pads > 0){
+    AgsHIndicator *hindicator;
+	
+    guint i;
+
+    for(i = audio_channels_old; i < audio_channels; i++){
+      hindicator = ags_hindicator_new();
+      gtk_box_pack_start(audiorec->hindicator_vbox,
+			 hindicator,
+			 FALSE, FALSE,
+			 8);
+    }
+
+    gtk_widget_show_all(audiorec->hindicator_vbox);
+  }else{
+    GList *list, *list_start;
+
+    list_start =
+      list = gtk_container_get_children(audiorec->hindicator_vbox);
+
+    list = g_list_nth(list_start,
+		      audio_channels);
+    
+    while(list != NULL){
+      gtk_widget_destroy(list->data);
+      
+      list = list->next;
+    }
+
+    g_list_free(list_start);
+  }
+}
+
+void
+ags_audiorec_resize_pads(AgsMachine *machine, GType type,
+			 guint pads, guint pads_old,
+			 gpointer data)
+{
+  AgsAudiorec *audiorec;
+
+  audiorec = AGS_AUDIOREC(machine);
+
+  if(type == AGS_TYPE_INPUT){
+    if(pads == 1 &&
+       pads_old == 0){
+      AgsHIndicator *hindicator;
+
+      guint audio_channels;
+      guint i;
+
+      audio_channels = machine->audio->audio_channels;
+
+      for(i = 0; i < audio_channels; i++){
+	hindicator = ags_hindicator_new();
+	gtk_box_pack_start(audiorec->hindicator_vbox,
+			   hindicator,
+			   FALSE, FALSE,
+			   8);
+      }
+
+      gtk_widget_show_all(audiorec->hindicator_vbox);
+    }else if(pads == 0){
+      GList *list, *list_start;
+
+      list_start = 
+	list = gtk_container_get_children(audiorec->hindicator_vbox);
+
+      while(list != NULL){
+	gtk_widget_destroy(list->data);
+      
+	list = list->next;
+      }
+
+      g_list_free(list_start);
+
+      /* depending on destination */
+      ags_audiorec_input_map_recall(audiorec,
+				    pads_old);
+    }else{
+      audiorec->mapped_input_pad = pads;
+    }
+  }else{
+    if(pads > pads_old){
+      /* depending on destination */
+      ags_audiorec_output_map_recall(audiorec,
+				     pads_old);
+    }else{
+      audiorec->mapped_output_pad = pads;
+    }
+  }
+}
+
+void
 ags_audiorec_read(AgsFile *file, xmlNode *node, AgsPlugin *plugin)
 {
   AgsAudiorec *gobject;
@@ -279,6 +603,13 @@ ags_audiorec_write(AgsFile *file, xmlNode *parent, AgsPlugin *plugin)
   return(node);
 }
 
+void
+ags_audiorec_open_filename(AgsAudiorec *audiorec,
+			   gchar *filename)
+{
+  //TODO:JK: implement me
+}
+
 /**
  * ags_audiorec_new:
  * @soundcard: the assigned soundcard.
diff --git a/ags/X/machine/ags_audiorec.h b/ags/X/machine/ags_audiorec.h
index 40ea7e3..c8ffd2d 100644
--- a/ags/X/machine/ags_audiorec.h
+++ b/ags/X/machine/ags_audiorec.h
@@ -46,6 +46,17 @@ struct _AgsAudiorec
 
   gchar *name;
   gchar *xml_type;
+
+  GtkEntry *filename;
+  GtkButton *open;
+
+  GtkRadioButton *keep_data;
+  GtkRadioButton *mix_data;
+  GtkRadioButton *replace_data;
+
+  GtkVBox *hindicator_vbox;
+
+  GtkFileChooserDialog *open_dialog;
 };
 
 struct _AgsAudiorecClass
@@ -55,6 +66,9 @@ struct _AgsAudiorecClass
 
 GType ags_audiorec_get_type(void);
 
+void ags_audiorec_open_filename(AgsAudiorec *audiorec,
+				gchar *filename);
+
 AgsAudiorec* ags_audiorec_new(GObject *soundcard);
 
 #endif /*__AGS_AUDIOREC_H__*/
diff --git a/ags/X/machine/ags_audiorec_callbacks.c b/ags/X/machine/ags_audiorec_callbacks.c
index a71ec57..87e04a6 100644
--- a/ags/X/machine/ags_audiorec_callbacks.c
+++ b/ags/X/machine/ags_audiorec_callbacks.c
@@ -18,3 +18,68 @@
  */
 
 #include <ags/X/machine/ags_audiorec_callbacks.h>
+
+#include <ags/i18n.h>
+
+void ags_audiorec_open_response_callback(GtkWidget *widget, gint response,
+					 AgsAudiorec *audiorec);
+
+void
+ags_audiorec_open_callback(GtkWidget *button, AgsAudiorec *audiorec)
+{
+  GtkFileChooserDialog *dialog;
+
+  if(audiorec->open_dialog != NULL){
+    return;
+  }
+  
+  audiorec->open_dialog = 
+    dialog = gtk_file_chooser_dialog_new(i18n("Open audio files"),
+					 (GtkWindow *) gtk_widget_get_toplevel((GtkWidget *) audiorec),
+					 GTK_FILE_CHOOSER_ACTION_OPEN,
+					 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+					 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+					 NULL);
+  gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog),
+				       FALSE);
+  gtk_widget_show_all((GtkWidget *) dialog);
+
+  g_signal_connect((GObject *) dialog, "response",
+		   G_CALLBACK(ags_audiorec_open_response_callback), audiorec);
+}
+
+void
+ags_audiorec_open_response_callback(GtkWidget *widget, gint response,
+				    AgsAudiorec *audiorec)
+{
+  if(response == GTK_RESPONSE_ACCEPT){
+    gchar *filename;
+
+    filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
+    gtk_entry_set_text(audiorec->filename,
+		       filename);
+    ags_audiorec_open_filename(audiorec,
+			       filename);
+  }
+
+  audiorec->open_dialog = NULL;
+  gtk_widget_destroy(widget);
+}
+
+void
+ags_audiorec_keep_data_callback(GtkWidget *button, AgsAudiorec *audiorec)
+{
+  //TODO:JK: implement me
+}
+
+void
+ags_audiorec_replace_data_callback(GtkWidget *button, AgsAudiorec *audiorec)
+{
+  //TODO:JK: implement me
+}
+
+void
+ags_audiorec_mix_data_callback(GtkWidget *button, AgsAudiorec *audiorec)
+{
+  //TODO:JK: implement me
+}
diff --git a/ags/X/machine/ags_audiorec_callbacks.h b/ags/X/machine/ags_audiorec_callbacks.h
index 8bf7ee9..ec8f895 100644
--- a/ags/X/machine/ags_audiorec_callbacks.h
+++ b/ags/X/machine/ags_audiorec_callbacks.h
@@ -27,4 +27,10 @@
 
 #include <ags/X/machine/ags_audiorec.h>
 
+void ags_audiorec_open_callback(GtkWidget *button, AgsAudiorec *audiorec);
+
+void ags_audiorec_keep_data_callback(GtkWidget *button, AgsAudiorec *audiorec);
+void ags_audiorec_replace_data_callback(GtkWidget *button, AgsAudiorec *audiorec);
+void ags_audiorec_mix_data_callback(GtkWidget *button, AgsAudiorec *audiorec);
+
 #endif /*__AGS_AUDIOREC_CALLBACKS_H__*/
diff --git a/ags/X/machine/ags_cell_pattern_callbacks.c b/ags/X/machine/ags_cell_pattern_callbacks.c
index f46905b..d07fa5b 100644
--- a/ags/X/machine/ags_cell_pattern_callbacks.c
+++ b/ags/X/machine/ags_cell_pattern_callbacks.c
@@ -543,7 +543,8 @@ ags_cell_pattern_init_channel_launch_callback(AgsTask *task, gpointer data)
   AgsRecycling *first_recycling, *last_recycling;
   AgsRecycling *end_recycling;
   AgsRecycling *recycling;
-
+  AgsNote *note;
+  
   AgsAddAudioSignal *add_audio_signal;
 
   AgsMutexManager *mutex_manager;
@@ -557,7 +558,6 @@ ags_cell_pattern_init_channel_launch_callback(AgsTask *task, gpointer data)
   pthread_mutex_t *recycling_mutex;
 
   channel = AGS_INIT_CHANNEL(task)->channel;
-  soundcard = channel->soundcard;
 
   mutex_manager = ags_mutex_manager_get_instance();
   application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
@@ -576,6 +576,8 @@ ags_cell_pattern_init_channel_launch_callback(AgsTask *task, gpointer data)
   
   /* get some fields */
   pthread_mutex_lock(channel_mutex);
+
+  soundcard = channel->soundcard;
   
   if(AGS_PLAYBACK(channel->playback) == NULL ||
      AGS_PLAYBACK(channel->playback)->recall_id[0] == NULL){    
@@ -601,7 +603,14 @@ ags_cell_pattern_init_channel_launch_callback(AgsTask *task, gpointer data)
 
   if(recall != NULL){
     AgsAudioSignal *audio_signal;
-      
+    AgsNote *note;
+    
+    pthread_mutex_lock(channel_mutex);
+
+    note = AGS_PLAYBACK(channel->playback)->play_note;
+
+    pthread_mutex_unlock(channel_mutex);
+
     /* get recycling mutex */
     pthread_mutex_lock(application_mutex);
 
@@ -629,23 +638,49 @@ ags_cell_pattern_init_channel_launch_callback(AgsTask *task, gpointer data)
   
       pthread_mutex_unlock(application_mutex);
 
-      /* audio signal */
-      audio_signal = ags_audio_signal_new((GObject *) soundcard,
-					  (GObject *) recycling,
-					  (GObject *) AGS_RECALL(recall->data)->recall_id);
-      /* add audio signal */
-      ags_recycling_create_audio_signal_with_defaults(recycling,
-						      audio_signal,
-						      0.0, 0);
-      audio_signal->stream_current = audio_signal->stream_beginning;
-      ags_connectable_connect(AGS_CONNECTABLE(audio_signal));
+      if(!AGS_RECALL(recall->data)->rt_safe){
+	/* audio signal */
+	audio_signal = ags_audio_signal_new((GObject *) soundcard,
+					    (GObject *) recycling,
+					    (GObject *) AGS_RECALL(recall->data)->recall_id);
+	g_object_set(audio_signal,
+		     "note", note,
+		     NULL);
+
+	/* add audio signal */
+	ags_recycling_create_audio_signal_with_defaults(recycling,
+							audio_signal,
+							0.0, 0);
+	audio_signal->stream_current = audio_signal->stream_beginning;
+	ags_connectable_connect(AGS_CONNECTABLE(audio_signal));
   
-      /*
-       * emit add_audio_signal on AgsRecycling
-       */
-      ags_recycling_add_audio_signal(recycling,
-				     audio_signal);
+	/*
+	 * emit add_audio_signal on AgsRecycling
+	 */
+	ags_recycling_add_audio_signal(recycling,
+				       audio_signal);
+      }else{
+	GList *list;
+
+	pthread_mutex_lock(recycling_mutex);
+	    
+	audio_signal = NULL;
+	list = ags_audio_signal_get_by_recall_id(recycling->audio_signal,
+						 AGS_RECALL(recall->data)->recall_id);
+	    
+	if(list != NULL){
+	  audio_signal = list->data;
+
+	  g_object_set(audio_signal,
+		       "note", note,
+		       NULL);
+	}
+
+	note->rt_offset = 0;
 
+	pthread_mutex_unlock(recycling_mutex);
+      }
+      
       /* iterate */
       pthread_mutex_lock(recycling_mutex);
       
diff --git a/ags/X/machine/ags_drum_input_line.c b/ags/X/machine/ags_drum_input_line.c
index a4f1fe1..68827e7 100644
--- a/ags/X/machine/ags_drum_input_line.c
+++ b/ags/X/machine/ags_drum_input_line.c
@@ -432,10 +432,15 @@ ags_drum_input_line_map_recall(AgsLine *line,
 
   AgsMutexManager *mutex_manager;
 
+  AgsConfig *config;
+  
   GList *list;
 
+  gchar *str;
+  
   guint pad, audio_channel;
   guint i;
+  gboolean rt_safe;
 
   pthread_mutex_t *application_mutex;
   pthread_mutex_t *source_mutex;
@@ -445,6 +450,8 @@ ags_drum_input_line_map_recall(AgsLine *line,
     return;
   }
 
+  config = ags_config_get_instance();
+  
   mutex_manager = ags_mutex_manager_get_instance();
   application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
 
@@ -566,34 +573,60 @@ ags_drum_input_line_map_recall(AgsLine *line,
 			    0);
 
   /* ags-stream */
-  ags_recall_factory_create(audio,
-			    NULL, NULL,
-			    "ags-stream",
-			    audio_channel, audio_channel + 1, 
-			    pad, pad + 1,
-			    (AGS_RECALL_FACTORY_INPUT |
-			     AGS_RECALL_FACTORY_PLAY |
-			     AGS_RECALL_FACTORY_RECALL | 
-			     AGS_RECALL_FACTORY_ADD),
-			    0);
+  rt_safe = TRUE;
 
-  /* set up dependencies */
-  pthread_mutex_lock(source_mutex);
-
-  list = ags_recall_find_type(source->play,
-			      AGS_TYPE_PLAY_CHANNEL_RUN);
-  play_channel_run = AGS_PLAY_CHANNEL_RUN(list->data);
-
-  list = ags_recall_find_type(source->play,
-			      AGS_TYPE_STREAM_CHANNEL_RUN);
-  stream_channel_run = AGS_STREAM_CHANNEL_RUN(list->data);
-
-  g_object_set(G_OBJECT(play_channel_run),
-	       "stream-channel-run", stream_channel_run,
-	       NULL);
+  str = ags_config_get_value(config,
+			     AGS_CONFIG_GENERIC,
+			     "rt-safe");
 
-  pthread_mutex_unlock(source_mutex);
+  if(str != NULL &&
+     !g_ascii_strncasecmp(str,
+			  "FALSE",
+			  6)){
+    rt_safe = FALSE;
+  }
 
+  if(!rt_safe){
+    ags_recall_factory_create(audio,
+			      NULL, NULL,
+			      "ags-stream",
+			      audio_channel, audio_channel + 1, 
+			      pad, pad + 1,
+			      (AGS_RECALL_FACTORY_INPUT |
+			       AGS_RECALL_FACTORY_PLAY |
+			       AGS_RECALL_FACTORY_RECALL | 
+			       AGS_RECALL_FACTORY_ADD),
+			      0);
+
+    /* set up dependencies */
+    pthread_mutex_lock(source_mutex);
+
+    list = ags_recall_find_type(source->play,
+				AGS_TYPE_PLAY_CHANNEL_RUN);
+    play_channel_run = AGS_PLAY_CHANNEL_RUN(list->data);
+
+    list = ags_recall_find_type(source->play,
+				AGS_TYPE_STREAM_CHANNEL_RUN);
+    stream_channel_run = AGS_STREAM_CHANNEL_RUN(list->data);
+
+    g_object_set(G_OBJECT(play_channel_run),
+		 "stream-channel-run", stream_channel_run,
+		 NULL);
+
+    pthread_mutex_unlock(source_mutex);
+  }else{
+    ags_recall_factory_create(audio,
+			      NULL, NULL,
+			      "ags-rt-stream",
+			      audio_channel, audio_channel + 1, 
+			      pad, pad + 1,
+			      (AGS_RECALL_FACTORY_INPUT |
+			       AGS_RECALL_FACTORY_PLAY |
+			       AGS_RECALL_FACTORY_RECALL | 
+			       AGS_RECALL_FACTORY_ADD),
+			      0);
+  }
+  
   /* call parent */
   AGS_LINE_CLASS(ags_drum_input_line_parent_class)->map_recall(line,
 							       output_pad_start);
diff --git a/ags/X/machine/ags_drum_output_line.c b/ags/X/machine/ags_drum_output_line.c
index 69bc490..18ebc27 100644
--- a/ags/X/machine/ags_drum_output_line.c
+++ b/ags/X/machine/ags_drum_output_line.c
@@ -274,6 +274,7 @@ ags_drum_output_line_map_recall(AgsLine *line,
 
   guint input_pads;
   guint audio_channels;
+  gboolean rt_safe;
   gboolean performance_mode;
 
   pthread_mutex_t *application_mutex;
@@ -325,15 +326,35 @@ ags_drum_output_line_map_recall(AgsLine *line,
   pthread_mutex_unlock(audio_mutex);
   
   /* remap for input */
+  rt_safe = TRUE;
+  performance_mode = TRUE;
+
+  str = ags_config_get_value(config,
+			     AGS_CONFIG_GENERIC,
+			     "rt-safe");
+
+  if(str != NULL &&
+     !g_ascii_strncasecmp(str,
+			  "FALSE",
+			  6)){
+    rt_safe = FALSE;
+  }
+
   str = ags_config_get_value(config,
 			     AGS_CONFIG_GENERIC,
 			     "engine-mode");
-  performance_mode = FALSE;
-  
+
   if(str != NULL &&
      !g_ascii_strncasecmp(str,
 			  "performance",
-			  12)){    
+			  12)){
+    performance_mode = TRUE;
+  }else{
+    performance_mode = FALSE;
+  }
+  
+  if(rt_safe ||
+     performance_mode){
     /* ags-copy */
     ags_recall_factory_create(audio,
 			      NULL, NULL,
diff --git a/ags/X/machine/ags_drum_output_line_callbacks.c b/ags/X/machine/ags_drum_output_line_callbacks.c
index 0ce91c3..50fb8ee 100644
--- a/ags/X/machine/ags_drum_output_line_callbacks.c
+++ b/ags/X/machine/ags_drum_output_line_callbacks.c
@@ -35,6 +35,7 @@ ags_drum_output_line_resize_pads_callback(AgsDrum *drum, GType channel_type,
 
   gchar *str;
 
+  gboolean rt_safe;
   gboolean performance_mode;
 
   audio = AGS_MACHINE(drum)->audio;
@@ -44,14 +45,38 @@ ags_drum_output_line_resize_pads_callback(AgsDrum *drum, GType channel_type,
   str = ags_config_get_value(config,
 			     AGS_CONFIG_GENERIC,
 			     "engine-mode");
-  performance_mode = FALSE;
+
+  rt_safe = TRUE;
+  performance_mode = TRUE;
+
+  str = ags_config_get_value(config,
+			     AGS_CONFIG_GENERIC,
+			     "rt-safe");
+
+  if(str != NULL &&
+     !g_ascii_strncasecmp(str,
+			  "FALSE",
+			  6)){
+    rt_safe = FALSE;
+  }
+
+  str = ags_config_get_value(config,
+			     AGS_CONFIG_GENERIC,
+			     "engine-mode");
+
+  if(str != NULL &&
+     !g_ascii_strncasecmp(str,
+			  "performance",
+			  12)){
+    performance_mode = TRUE;
+  }else{
+    performance_mode = FALSE;
+  }
 
   if(channel_type == AGS_TYPE_INPUT){
     if(pads_new > pads_old){
-      if(str != NULL &&
-	 !g_ascii_strncasecmp(str,
-			      "performance",
-			      12)){
+      if(rt_safe ||
+	 performance_mode){
 	/* ags-copy */
 	ags_recall_factory_create(audio,
 				  NULL, NULL,
diff --git a/ags/X/machine/ags_dssi_bridge.c b/ags/X/machine/ags_dssi_bridge.c
index 846765a..d4c1186 100644
--- a/ags/X/machine/ags_dssi_bridge.c
+++ b/ags/X/machine/ags_dssi_bridge.c
@@ -1165,8 +1165,7 @@ ags_dssi_bridge_map_recall(AgsMachine *machine)
 			    0, 0,
 			    (AGS_RECALL_FACTORY_OUTPUT |
 			     AGS_RECALL_FACTORY_ADD |
-			     AGS_RECALL_FACTORY_PLAY |
-			     AGS_RECALL_FACTORY_RECALL),
+			     AGS_RECALL_FACTORY_PLAY),
 			    0);
 
   pthread_mutex_lock(audio_mutex);
@@ -1191,8 +1190,7 @@ ags_dssi_bridge_map_recall(AgsMachine *machine)
 			    0, 0,
 			    (AGS_RECALL_FACTORY_OUTPUT |
 			     AGS_RECALL_FACTORY_ADD |
-			     AGS_RECALL_FACTORY_PLAY |
-			     AGS_RECALL_FACTORY_RECALL),
+			     AGS_RECALL_FACTORY_PLAY),
 			    0);
   
   pthread_mutex_lock(audio_mutex);
@@ -1353,6 +1351,7 @@ ags_dssi_bridge_input_map_recall(AgsDssiBridge *dssi_bridge,
 
   guint input_pads;
   guint audio_channels;
+  gboolean rt_safe;
   gboolean performance_mode;
 
   pthread_mutex_t *application_mutex;
@@ -1453,15 +1452,35 @@ ags_dssi_bridge_input_map_recall(AgsDssiBridge *dssi_bridge,
   }
 
   /* map dependending on output */
+  rt_safe = TRUE;
+  performance_mode = TRUE;
+
+  str = ags_config_get_value(config,
+			     AGS_CONFIG_GENERIC,
+			     "rt-safe");
+
+  if(str != NULL &&
+     !g_ascii_strncasecmp(str,
+			  "FALSE",
+			  6)){
+    rt_safe = FALSE;
+  }
+
   str = ags_config_get_value(config,
 			     AGS_CONFIG_GENERIC,
 			     "engine-mode");
-  performance_mode = FALSE;
-  
+
   if(str != NULL &&
      !g_ascii_strncasecmp(str,
 			  "performance",
 			  12)){
+    performance_mode = TRUE;
+  }else{
+    performance_mode = FALSE;
+  }
+
+  if(rt_safe ||
+     performance_mode){
     /* ags-copy */
     ags_recall_factory_create(audio,
 			      NULL, NULL,
@@ -1500,16 +1519,29 @@ ags_dssi_bridge_input_map_recall(AgsDssiBridge *dssi_bridge,
 			    0);
 
   /* ags-stream */
-  ags_recall_factory_create(audio,
-			    NULL, NULL,
-			    "ags-stream",
-			    audio_channel_start, audio_channels, 
-			    input_pad_start, input_pads,
-			    (AGS_RECALL_FACTORY_INPUT |
-			     AGS_RECALL_FACTORY_PLAY |
-			     AGS_RECALL_FACTORY_RECALL | 
-			     AGS_RECALL_FACTORY_ADD),
-			    0);
+  if(!rt_safe){
+    ags_recall_factory_create(audio,
+			      NULL, NULL,
+			      "ags-stream",
+			      audio_channel_start, audio_channels, 
+			      input_pad_start, input_pads,
+			      (AGS_RECALL_FACTORY_INPUT |
+			       AGS_RECALL_FACTORY_PLAY |
+			       AGS_RECALL_FACTORY_RECALL | 
+			       AGS_RECALL_FACTORY_ADD),
+			      0);
+  }else{
+    ags_recall_factory_create(audio,
+			      NULL, NULL,
+			      "ags-rt-stream",
+			      audio_channel_start, audio_channels, 
+			      input_pad_start, input_pads,
+			      (AGS_RECALL_FACTORY_INPUT |
+			       AGS_RECALL_FACTORY_PLAY |
+			       AGS_RECALL_FACTORY_RECALL | 
+			       AGS_RECALL_FACTORY_ADD),
+			      0);
+  }
   
   dssi_bridge->mapped_input_pad = input_pads;
 }
@@ -1534,6 +1566,7 @@ ags_dssi_bridge_output_map_recall(AgsDssiBridge *dssi_bridge,
 
   guint output_pads, input_pads;
   guint audio_channels;
+  gboolean rt_safe;
   gboolean performance_mode;
 
   pthread_mutex_t *application_mutex;
@@ -1569,16 +1602,36 @@ ags_dssi_bridge_output_map_recall(AgsDssiBridge *dssi_bridge,
   pthread_mutex_unlock(audio_mutex);
 
   /* map dependending on output */
+  rt_safe = TRUE;
+  performance_mode = TRUE;
+
+  str = ags_config_get_value(config,
+			     AGS_CONFIG_GENERIC,
+			     "rt-safe");
+
+  if(str != NULL &&
+     !g_ascii_strncasecmp(str,
+			  "FALSE",
+			  6)){
+    rt_safe = FALSE;
+  }
+
   str = ags_config_get_value(config,
 			     AGS_CONFIG_GENERIC,
 			     "engine-mode");
-  performance_mode = FALSE;
 
-  /* remap for input */
   if(str != NULL &&
      !g_ascii_strncasecmp(str,
 			  "performance",
 			  12)){
+    performance_mode = TRUE;
+  }else{
+    performance_mode = FALSE;
+  }
+
+  /* remap for input */
+  if(rt_safe ||
+     performance_mode){
     /* ags-copy */
     ags_recall_factory_create(audio,
 			      NULL, NULL,
diff --git a/ags/X/machine/ags_ffplayer.c b/ags/X/machine/ags_ffplayer.c
index e1b6973..60dcc21 100644
--- a/ags/X/machine/ags_ffplayer.c
+++ b/ags/X/machine/ags_ffplayer.c
@@ -968,6 +968,7 @@ ags_ffplayer_resize_audio_channels(AgsMachine *machine,
   gchar *str;
 
   guint input_pads;
+  gboolean rt_safe;
   gboolean performance_mode;
 
   pthread_mutex_t *application_mutex;
@@ -1001,12 +1002,35 @@ ags_ffplayer_resize_audio_channels(AgsMachine *machine,
     str = ags_config_get_value(config,
 			       AGS_CONFIG_GENERIC,
 			       "engine-mode");
-    performance_mode = FALSE;
-  
+    rt_safe = TRUE;
+    performance_mode = TRUE;
+
+    str = ags_config_get_value(config,
+			       AGS_CONFIG_GENERIC,
+			       "rt-safe");
+
+    if(str != NULL &&
+       !g_ascii_strncasecmp(str,
+			    "FALSE",
+			    6)){
+      rt_safe = FALSE;
+    }
+
+    str = ags_config_get_value(config,
+			       AGS_CONFIG_GENERIC,
+			       "engine-mode");
+
     if(str != NULL &&
        !g_ascii_strncasecmp(str,
 			    "performance",
 			    12)){
+      performance_mode = TRUE;
+    }else{
+      performance_mode = FALSE;
+    }
+  
+    if(rt_safe ||
+       performance_mode){
       /* ags-copy */
       ags_recall_factory_create(audio,
 				NULL, NULL,
@@ -1057,17 +1081,30 @@ ags_ffplayer_resize_audio_channels(AgsMachine *machine,
 			      0);
 
     /* ags-stream */
-    ags_recall_factory_create(audio,
-			      NULL, NULL,
-			      "ags-stream",
-			      audio_channels_old, audio_channels, 
-			      0, input_pads,
-			      (AGS_RECALL_FACTORY_INPUT |
-			       AGS_RECALL_FACTORY_PLAY |
-			       AGS_RECALL_FACTORY_RECALL | 
-			       AGS_RECALL_FACTORY_ADD),
-			      0);
-
+    if(!rt_safe){
+      ags_recall_factory_create(audio,
+				NULL, NULL,
+				"ags-stream",
+				audio_channels_old, audio_channels, 
+				0, input_pads,
+				(AGS_RECALL_FACTORY_INPUT |
+				 AGS_RECALL_FACTORY_PLAY |
+				 AGS_RECALL_FACTORY_RECALL | 
+				 AGS_RECALL_FACTORY_ADD),
+				0);
+    }else{
+      ags_recall_factory_create(audio,
+				NULL, NULL,
+				"ags-rt-stream",
+				audio_channels_old, audio_channels, 
+				0, input_pads,
+				(AGS_RECALL_FACTORY_INPUT |
+				 AGS_RECALL_FACTORY_PLAY |
+				 AGS_RECALL_FACTORY_RECALL | 
+				 AGS_RECALL_FACTORY_ADD),
+				0);
+    }
+    
     /* AgsOutput */
     /* ags-stream */
     if(!performance_mode){
@@ -1168,6 +1205,7 @@ ags_ffplayer_input_map_recall(AgsFFPlayer *ffplayer, guint input_pad_start)
 
   guint input_pads;
   guint audio_channels;
+  gboolean rt_safe;
   gboolean performance_mode;
 
   pthread_mutex_t *application_mutex;
@@ -1202,16 +1240,36 @@ ags_ffplayer_input_map_recall(AgsFFPlayer *ffplayer, guint input_pad_start)
   pthread_mutex_unlock(audio_mutex);
 
   /* map dependending on output */
-  str = ags_config_get_value(config,
-			     AGS_CONFIG_GENERIC,
-			     "engine-mode");
-  performance_mode = FALSE;
+    rt_safe = TRUE;
+    performance_mode = TRUE;
+
+    str = ags_config_get_value(config,
+			       AGS_CONFIG_GENERIC,
+			       "rt-safe");
+
+    if(str != NULL &&
+       !g_ascii_strncasecmp(str,
+			    "FALSE",
+			    6)){
+      rt_safe = FALSE;
+    }
+
+    str = ags_config_get_value(config,
+			       AGS_CONFIG_GENERIC,
+			       "engine-mode");
+
+    if(str != NULL &&
+       !g_ascii_strncasecmp(str,
+			    "performance",
+			    12)){
+      performance_mode = TRUE;
+    }else{
+      performance_mode = FALSE;
+    }
   
   /* remap for input */
-  if(str != NULL &&
-     !g_ascii_strncasecmp(str,
-			  "performance",
-			  12)){
+  if(rt_safe ||
+     performance_mode){
     /* ags-copy */
     ags_recall_factory_create(audio,
 			      NULL, NULL,
@@ -1273,16 +1331,29 @@ ags_ffplayer_input_map_recall(AgsFFPlayer *ffplayer, guint input_pad_start)
 			     AGS_RECALL_FACTORY_ADD),
 			    0);
   /* ags-stream */
-  ags_recall_factory_create(audio,
-			    NULL, NULL,
-			    "ags-stream",
-			    0, audio_channels,
-			    input_pad_start, input_pads,
-			    (AGS_RECALL_FACTORY_INPUT |
-			     AGS_RECALL_FACTORY_PLAY |
-			     AGS_RECALL_FACTORY_RECALL | 
-			     AGS_RECALL_FACTORY_ADD),
-			    0);
+  if(!rt_safe){
+    ags_recall_factory_create(audio,
+			      NULL, NULL,
+			      "ags-stream",
+			      0, audio_channels,
+			      input_pad_start, input_pads,
+			      (AGS_RECALL_FACTORY_INPUT |
+			       AGS_RECALL_FACTORY_PLAY |
+			       AGS_RECALL_FACTORY_RECALL | 
+			       AGS_RECALL_FACTORY_ADD),
+			      0);
+  }else{
+    ags_recall_factory_create(audio,
+			      NULL, NULL,
+			      "ags-rt-stream",
+			      0, audio_channels,
+			      input_pad_start, input_pads,
+			      (AGS_RECALL_FACTORY_INPUT |
+			       AGS_RECALL_FACTORY_PLAY |
+			       AGS_RECALL_FACTORY_RECALL | 
+			       AGS_RECALL_FACTORY_ADD),
+			      0);
+  }
   
   ffplayer->mapped_input_pad = input_pads;
 }
@@ -1300,6 +1371,7 @@ ags_ffplayer_output_map_recall(AgsFFPlayer *ffplayer, guint output_pad_start)
 
   guint output_pads, input_pads;
   guint audio_channels;
+  gboolean rt_safe;
   gboolean performance_mode;
 
   pthread_mutex_t *application_mutex;
@@ -1335,16 +1407,36 @@ ags_ffplayer_output_map_recall(AgsFFPlayer *ffplayer, guint output_pad_start)
   pthread_mutex_unlock(audio_mutex);
   
   /* map dependending on output */
+  rt_safe = TRUE;
+  performance_mode = TRUE;
+
+  str = ags_config_get_value(config,
+			     AGS_CONFIG_GENERIC,
+			     "rt-safe");
+
+  if(str != NULL &&
+     !g_ascii_strncasecmp(str,
+			  "FALSE",
+			  6)){
+    rt_safe = FALSE;
+  }
+
   str = ags_config_get_value(config,
 			     AGS_CONFIG_GENERIC,
 			     "engine-mode");
-  performance_mode = FALSE;
 
-  /* remap for input */
   if(str != NULL &&
      !g_ascii_strncasecmp(str,
 			  "performance",
 			  12)){
+    performance_mode = TRUE;
+  }else{
+    performance_mode = FALSE;
+  }
+
+  /* remap for input */
+  if(rt_safe ||
+     performance_mode){
     /* ags-copy */
     ags_recall_factory_create(audio,
 			      NULL, NULL,
diff --git a/ags/X/machine/ags_lv2_bridge.c b/ags/X/machine/ags_lv2_bridge.c
index 96e0b42..6d4f9b8 100644
--- a/ags/X/machine/ags_lv2_bridge.c
+++ b/ags/X/machine/ags_lv2_bridge.c
@@ -1537,6 +1537,7 @@ ags_lv2_bridge_input_map_recall(AgsLv2Bridge *lv2_bridge,
 
   guint input_pads;
   guint audio_channels;
+  gboolean rt_safe;
   gboolean performance_mode;
 
   pthread_mutex_t *application_mutex;
@@ -1638,15 +1639,35 @@ ags_lv2_bridge_input_map_recall(AgsLv2Bridge *lv2_bridge,
     }
 
     /* map dependending on output */
+    rt_safe = TRUE;
+    performance_mode = TRUE;
+
+    str = ags_config_get_value(config,
+			       AGS_CONFIG_GENERIC,
+			       "rt-safe");
+
+    if(str != NULL &&
+       !g_ascii_strncasecmp(str,
+			    "FALSE",
+			    6)){
+      rt_safe = FALSE;
+    }
+
     str = ags_config_get_value(config,
 			       AGS_CONFIG_GENERIC,
 			       "engine-mode");
-    performance_mode = FALSE;
-  
+
     if(str != NULL &&
        !g_ascii_strncasecmp(str,
 			    "performance",
 			    12)){
+      performance_mode = TRUE;
+    }else{
+      performance_mode = FALSE;
+    }
+    
+    if(rt_safe ||
+       performance_mode){
       /* ags-copy */
       ags_recall_factory_create(audio,
 				NULL, NULL,
@@ -1686,16 +1707,29 @@ ags_lv2_bridge_input_map_recall(AgsLv2Bridge *lv2_bridge,
 			       AGS_RECALL_FACTORY_ADD),
 			      0);
     /* ags-stream */
-    ags_recall_factory_create(audio,
-			      NULL, NULL,
-			      "ags-stream",
-			      audio_channel_start, audio_channels, 
-			      input_pad_start, input_pads,
-			      (AGS_RECALL_FACTORY_INPUT |
-			       AGS_RECALL_FACTORY_PLAY |
-			       AGS_RECALL_FACTORY_RECALL | 
-			       AGS_RECALL_FACTORY_ADD),
-			      0);
+    if(!rt_safe){
+      ags_recall_factory_create(audio,
+				NULL, NULL,
+				"ags-stream",
+				audio_channel_start, audio_channels, 
+				input_pad_start, input_pads,
+				(AGS_RECALL_FACTORY_INPUT |
+				 AGS_RECALL_FACTORY_PLAY |
+				 AGS_RECALL_FACTORY_RECALL | 
+				 AGS_RECALL_FACTORY_ADD),
+				0);
+    }else{
+      ags_recall_factory_create(audio,
+				NULL, NULL,
+				"ags-rt-stream",
+				audio_channel_start, audio_channels, 
+				input_pad_start, input_pads,
+				(AGS_RECALL_FACTORY_INPUT |
+				 AGS_RECALL_FACTORY_PLAY |
+				 AGS_RECALL_FACTORY_RECALL | 
+				 AGS_RECALL_FACTORY_ADD),
+				0);
+    }      
   }
   
   lv2_bridge->mapped_input_pad = input_pads;
@@ -1722,6 +1756,7 @@ ags_lv2_bridge_output_map_recall(AgsLv2Bridge *lv2_bridge,
 
   guint output_pads, input_pads;
   guint audio_channels;
+  gboolean rt_safe;
   gboolean performance_mode;
 
   pthread_mutex_t *application_mutex;
@@ -1758,16 +1793,36 @@ ags_lv2_bridge_output_map_recall(AgsLv2Bridge *lv2_bridge,
 
   if((AGS_MACHINE_IS_SYNTHESIZER & (AGS_MACHINE(lv2_bridge)->flags)) != 0){
     /* map dependending on output */
+    rt_safe = TRUE;
+    performance_mode = TRUE;
+
+    str = ags_config_get_value(config,
+			       AGS_CONFIG_GENERIC,
+			       "rt-safe");
+
+    if(str != NULL &&
+       !g_ascii_strncasecmp(str,
+			    "FALSE",
+			    6)){
+      rt_safe = FALSE;
+    }
+
     str = ags_config_get_value(config,
 			       AGS_CONFIG_GENERIC,
 			       "engine-mode");
-    performance_mode = FALSE;
-  
-    /* remap for input */
+
     if(str != NULL &&
        !g_ascii_strncasecmp(str,
 			    "performance",
 			    12)){
+      performance_mode = TRUE;
+    }else{
+      performance_mode = FALSE;
+    }
+  
+    /* remap for input */
+    if(rt_safe ||
+       performance_mode){
       /* ags-copy */
       ags_recall_factory_create(audio,
 				NULL, NULL,
diff --git a/ags/X/machine/ags_matrix.c b/ags/X/machine/ags_matrix.c
index 71c2743..d40239c 100644
--- a/ags/X/machine/ags_matrix.c
+++ b/ags/X/machine/ags_matrix.c
@@ -871,6 +871,7 @@ ags_matrix_input_map_recall(AgsMatrix *matrix,
   guint input_pads;
   guint audio_channels;
   guint i, j;
+  gboolean rt_safe;
   gboolean performance_mode;
   
   pthread_mutex_t *application_mutex;
@@ -960,16 +961,36 @@ ags_matrix_input_map_recall(AgsMatrix *matrix,
   }
   
   /* map dependending on output */
+  rt_safe = TRUE;
+  performance_mode = TRUE;
+
+  str = ags_config_get_value(config,
+			     AGS_CONFIG_GENERIC,
+			     "rt-safe");
+
+  if(str != NULL &&
+     !g_ascii_strncasecmp(str,
+			  "FALSE",
+			  6)){
+    rt_safe = FALSE;
+  }
+
   str = ags_config_get_value(config,
 			     AGS_CONFIG_GENERIC,
 			     "engine-mode");
-  performance_mode = FALSE;
 
-  /* remap for input */
   if(str != NULL &&
      !g_ascii_strncasecmp(str,
 			  "performance",
 			  12)){
+    performance_mode = TRUE;
+  }else{
+    performance_mode = FALSE;
+  }
+
+  /* remap for input */
+  if(rt_safe ||
+     performance_mode){
     /* ags-copy */
     ags_recall_factory_create(audio,
 			      NULL, NULL,
@@ -1020,16 +1041,29 @@ ags_matrix_input_map_recall(AgsMatrix *matrix,
 			    0);
 
   /* ags-stream */
-  ags_recall_factory_create(audio,
-			    NULL, NULL,
-			    "ags-stream",
-			    0, audio_channels, 
-			    input_pad_start, input_pads,
-			    (AGS_RECALL_FACTORY_INPUT |
-			     AGS_RECALL_FACTORY_PLAY |
-			     AGS_RECALL_FACTORY_RECALL | 
-			     AGS_RECALL_FACTORY_ADD),
-			    0);
+  if(!rt_safe){
+    ags_recall_factory_create(audio,
+			      NULL, NULL,
+			      "ags-stream",
+			      0, audio_channels, 
+			      input_pad_start, input_pads,
+			      (AGS_RECALL_FACTORY_INPUT |
+			       AGS_RECALL_FACTORY_PLAY |
+			       AGS_RECALL_FACTORY_RECALL | 
+			       AGS_RECALL_FACTORY_ADD),
+			      0);
+  }else{
+    ags_recall_factory_create(audio,
+			      NULL, NULL,
+			      "ags-rt-stream",
+			      0, audio_channels, 
+			      input_pad_start, input_pads,
+			      (AGS_RECALL_FACTORY_INPUT |
+			       AGS_RECALL_FACTORY_PLAY |
+			       AGS_RECALL_FACTORY_RECALL | 
+			       AGS_RECALL_FACTORY_ADD),
+			      0);
+  }
   
   matrix->mapped_input_pad = input_pads;
 }
@@ -1049,6 +1083,7 @@ ags_matrix_output_map_recall(AgsMatrix *matrix,
   guint input_pad_start;
   guint output_pads, input_pads;
   guint audio_channels;
+  gboolean rt_safe;
   gboolean performance_mode;
 
   pthread_mutex_t *application_mutex;
@@ -1090,16 +1125,36 @@ ags_matrix_output_map_recall(AgsMatrix *matrix,
   }
   
   /* map dependending on output */
+  rt_safe = TRUE;
+  performance_mode = TRUE;
+
+  str = ags_config_get_value(config,
+			     AGS_CONFIG_GENERIC,
+			     "rt-safe");
+
+  if(str != NULL &&
+     !g_ascii_strncasecmp(str,
+			  "FALSE",
+			  6)){
+    rt_safe = FALSE;
+  }
+
   str = ags_config_get_value(config,
 			     AGS_CONFIG_GENERIC,
 			     "engine-mode");
-  performance_mode = FALSE;
 
-  /* remap for input */
   if(str != NULL &&
      !g_ascii_strncasecmp(str,
 			  "performance",
 			  12)){
+    performance_mode = TRUE;
+  }else{
+    performance_mode = FALSE;
+  }
+
+  /* remap for input */
+  if(rt_safe ||
+     performance_mode){
     /* ags-copy */
     ags_recall_factory_create(audio,
 			      NULL, NULL,
diff --git a/ags/X/machine/ags_panel.c b/ags/X/machine/ags_panel.c
index a833705..9c0a21e 100644
--- a/ags/X/machine/ags_panel.c
+++ b/ags/X/machine/ags_panel.c
@@ -174,6 +174,8 @@ ags_panel_init(AgsPanel *panel)
   ags_machine_popup_add_connection_options((AgsMachine *) panel,
 					   (AGS_MACHINE_POPUP_CONNECTION_EDITOR));
 
+  AGS_MACHINE(panel)->connection_flags |= AGS_MACHINE_SHOW_AUDIO_OUTPUT_CONNECTION;
+
   AGS_MACHINE(panel)->audio->flags |= (AGS_AUDIO_SYNC);
   AGS_MACHINE(panel)->input_pad_type = AGS_TYPE_PANEL_INPUT_PAD;
 
diff --git a/ags/X/machine/ags_syncsynth.c b/ags/X/machine/ags_syncsynth.c
index 0452bbb..7d16ea7 100644
--- a/ags/X/machine/ags_syncsynth.c
+++ b/ags/X/machine/ags_syncsynth.c
@@ -752,7 +752,7 @@ ags_syncsynth_resize_audio_channels(AgsMachine *machine,
   gchar *str;
 
   guint output_pads, input_pads;
-  
+  gboolean rt_safe;
   gboolean performance_mode;
 
   pthread_mutex_t *application_mutex;
@@ -785,15 +785,35 @@ ags_syncsynth_resize_audio_channels(AgsMachine *machine,
 
   if(audio_channels > audio_channels_old){
     /* map dependending on output */
+    rt_safe = TRUE;
+    performance_mode = TRUE;
+
+    str = ags_config_get_value(config,
+			       AGS_CONFIG_GENERIC,
+			       "rt-safe");
+
+    if(str != NULL &&
+       !g_ascii_strncasecmp(str,
+			    "FALSE",
+			    6)){
+      rt_safe = FALSE;
+    }
+
     str = ags_config_get_value(config,
 			       AGS_CONFIG_GENERIC,
 			       "engine-mode");
-    performance_mode = FALSE;
-  
+
     if(str != NULL &&
        !g_ascii_strncasecmp(str,
 			    "performance",
 			    12)){
+      performance_mode = TRUE;
+    }else{
+      performance_mode = FALSE;
+    }
+
+    if(rt_safe ||
+       performance_mode){
       /* ags-copy */
       ags_recall_factory_create(audio,
 				NULL, NULL,
@@ -844,17 +864,30 @@ ags_syncsynth_resize_audio_channels(AgsMachine *machine,
 			      0);
 
     /* ags-stream */
-    ags_recall_factory_create(audio,
-			      NULL, NULL,
-			      "ags-stream",
-			      audio_channels_old, audio_channels, 
-			      0, input_pads,
-			      (AGS_RECALL_FACTORY_INPUT |
-			       AGS_RECALL_FACTORY_PLAY |
-			       AGS_RECALL_FACTORY_RECALL | 
-			       AGS_RECALL_FACTORY_ADD),
-			      0);
-
+    if(!rt_safe){
+      ags_recall_factory_create(audio,
+				NULL, NULL,
+				"ags-stream",
+				audio_channels_old, audio_channels, 
+				0, input_pads,
+				(AGS_RECALL_FACTORY_INPUT |
+				 AGS_RECALL_FACTORY_PLAY |
+				 AGS_RECALL_FACTORY_RECALL | 
+				 AGS_RECALL_FACTORY_ADD),
+				0);
+    }else{
+      ags_recall_factory_create(audio,
+				NULL, NULL,
+				"ags-rt-stream",
+				audio_channels_old, audio_channels, 
+				0, input_pads,
+				(AGS_RECALL_FACTORY_INPUT |
+				 AGS_RECALL_FACTORY_PLAY |
+				 AGS_RECALL_FACTORY_RECALL | 
+				 AGS_RECALL_FACTORY_ADD),
+				0);
+    }
+    
     /* AgsOutput */
     /* ags-stream */
     if(!performance_mode){
@@ -1036,6 +1069,7 @@ ags_syncsynth_input_map_recall(AgsSyncsynth *syncsynth,
 
   guint input_pads;
   guint audio_channels;
+  gboolean rt_safe;
   gboolean performance_mode;
 
   pthread_mutex_t *application_mutex;
@@ -1069,16 +1103,36 @@ ags_syncsynth_input_map_recall(AgsSyncsynth *syncsynth,
   pthread_mutex_unlock(audio_mutex);
 
   /* map dependending on output */
+  rt_safe = TRUE;
+  performance_mode = TRUE;
+
+  str = ags_config_get_value(config,
+			     AGS_CONFIG_GENERIC,
+			     "rt-safe");
+
+  if(str != NULL &&
+     !g_ascii_strncasecmp(str,
+			  "FALSE",
+			  6)){
+    rt_safe = FALSE;
+  }
+
   str = ags_config_get_value(config,
 			     AGS_CONFIG_GENERIC,
 			     "engine-mode");
-  performance_mode = FALSE;
-  
-  /* remap for input */
+
   if(str != NULL &&
      !g_ascii_strncasecmp(str,
 			  "performance",
 			  12)){
+    performance_mode = TRUE;
+  }else{
+    performance_mode = FALSE;
+  }
+
+  /* remap for input */
+  if(rt_safe ||
+     performance_mode){
     /* ags-copy */
     ags_recall_factory_create(audio,
 			      NULL, NULL,
@@ -1141,16 +1195,29 @@ ags_syncsynth_input_map_recall(AgsSyncsynth *syncsynth,
 			    0);
   
   /* ags-stream */
-  ags_recall_factory_create(audio,
-			    NULL, NULL,
-			    "ags-stream",
-			    0, audio_channels, 
-			    input_pad_start, input_pads,
-			    (AGS_RECALL_FACTORY_INPUT |
-			     AGS_RECALL_FACTORY_PLAY |
-			     AGS_RECALL_FACTORY_RECALL | 
-			     AGS_RECALL_FACTORY_ADD),
-			    0);
+  if(!rt_safe){
+    ags_recall_factory_create(audio,
+			      NULL, NULL,
+			      "ags-stream",
+			      0, audio_channels, 
+			      input_pad_start, input_pads,
+			      (AGS_RECALL_FACTORY_INPUT |
+			       AGS_RECALL_FACTORY_PLAY |
+			       AGS_RECALL_FACTORY_RECALL | 
+			       AGS_RECALL_FACTORY_ADD),
+			      0);
+  }else{
+    ags_recall_factory_create(audio,
+			      NULL, NULL,
+			      "ags-rt-stream",
+			      0, audio_channels, 
+			      input_pad_start, input_pads,
+			      (AGS_RECALL_FACTORY_INPUT |
+			       AGS_RECALL_FACTORY_PLAY |
+			       AGS_RECALL_FACTORY_RECALL | 
+			       AGS_RECALL_FACTORY_ADD),
+			      0);
+  }
   
   syncsynth->mapped_input_pad = input_pads;
 }
@@ -1170,6 +1237,7 @@ ags_syncsynth_output_map_recall(AgsSyncsynth *syncsynth,
   guint input_pad_start;
   guint output_pads, input_pads;
   guint audio_channels;
+  gboolean rt_safe;
   gboolean performance_mode;
 
   pthread_mutex_t *application_mutex;
@@ -1207,16 +1275,36 @@ ags_syncsynth_output_map_recall(AgsSyncsynth *syncsynth,
   pthread_mutex_unlock(audio_mutex);
   
   /* map dependending on output */
+  rt_safe = TRUE;
+  performance_mode = TRUE;
+
+  str = ags_config_get_value(config,
+			     AGS_CONFIG_GENERIC,
+			     "rt-safe");
+
+  if(str != NULL &&
+     !g_ascii_strncasecmp(str,
+			  "FALSE",
+			  6)){
+    rt_safe = FALSE;
+  }
+
   str = ags_config_get_value(config,
 			     AGS_CONFIG_GENERIC,
 			     "engine-mode");
-  performance_mode = FALSE;
 
-  /* remap for input */
   if(str != NULL &&
      !g_ascii_strncasecmp(str,
 			  "performance",
 			  12)){
+    performance_mode = TRUE;
+  }else{
+    performance_mode = FALSE;
+  }
+
+  /* remap for input */
+  if(rt_safe ||
+     performance_mode){
     /* ags-copy */
     ags_recall_factory_create(audio,
 			      NULL, NULL,
diff --git a/ags/X/thread/ags_gui_thread.c b/ags/X/thread/ags_gui_thread.c
index 371ed27..ad7682e 100644
--- a/ags/X/thread/ags_gui_thread.c
+++ b/ags/X/thread/ags_gui_thread.c
@@ -23,7 +23,7 @@
 #include <ags/libags.h>
 #include <ags/libags-audio.h>
 
-#include <ags/X/ags_xorg_application_context.h>
+#include <ags/X/ags_ui_provider.h>
 #include <ags/X/ags_window.h>
 
 #include <ags/X/file/ags_simple_file.h>
@@ -372,7 +372,7 @@ ags_gui_thread_do_poll_loop(void *ptr)
   AgsPollingThread *polling_thread;
   AgsThread *thread;
   
-  AgsXorgApplicationContext *xorg_application_context;
+  AgsApplicationContext *application_context;
 
   GMainContext *main_context;
   GSourceFuncs task_funcs;
@@ -389,7 +389,7 @@ ags_gui_thread_do_poll_loop(void *ptr)
   gui_thread = (AgsGuiThread *) ptr;
   thread = (AgsThread *) ptr;
   
-  xorg_application_context = ags_application_context_get_instance();
+  application_context = ags_application_context_get_instance();
 
   main_context = gui_thread->main_context;
 
@@ -457,14 +457,14 @@ ags_gui_thread_do_poll_loop(void *ptr)
 		  main_context);
 
   /* wait for audio loop */
-  while(g_atomic_int_get(&(xorg_application_context->gui_ready)) == 0){
+  while(!ags_ui_provider_get_gui_ready(AGS_UI_PROVIDER(application_context))){
     usleep(500000);
   }
 
-  task_thread = ags_thread_find_type(AGS_APPLICATION_CONTEXT(xorg_application_context)->main_loop,
+  task_thread = ags_thread_find_type(AGS_APPLICATION_CONTEXT(application_context)->main_loop,
 				     AGS_TYPE_TASK_THREAD);
 
-  polling_thread = (AgsPollingThread *) ags_thread_find_type(AGS_APPLICATION_CONTEXT(xorg_application_context)->main_loop,
+  polling_thread = (AgsPollingThread *) ags_thread_find_type(AGS_APPLICATION_CONTEXT(application_context)->main_loop,
 							     AGS_TYPE_POLLING_THREAD);
   
   /* poll */
@@ -1186,7 +1186,7 @@ gboolean
 ags_gui_thread_animation_prepare(GSource *source,
 				 gint *timeout_)
 {
-  AgsXorgApplicationContext *xorg_application_context;
+  AgsApplicationContext *application_context;
 
   AgsGuiThread *gui_thread;
   
@@ -1196,8 +1196,8 @@ ags_gui_thread_animation_prepare(GSource *source,
 
   guint nth;
   
-  xorg_application_context = ags_application_context_get_instance();
-  main_loop = AGS_APPLICATION_CONTEXT(xorg_application_context)->main_loop;
+  application_context = ags_application_context_get_instance();
+  main_loop = AGS_APPLICATION_CONTEXT(application_context)->main_loop;
   
   gui_thread = ags_thread_find_type(main_loop,
 				    AGS_TYPE_GUI_THREAD);
@@ -1211,7 +1211,7 @@ ags_gui_thread_animation_prepare(GSource *source,
   pthread_mutex_unlock(log->mutex);
 
   if(nth > gui_thread->nth_message ||
-     !g_atomic_int_get(&(xorg_application_context->show_animation))){
+     !ags_ui_provider_get_show_animation(AGS_UI_PROVIDER(application_context))){
     if(timeout_ != NULL){
       *timeout_ = 0;
     }
@@ -1229,7 +1229,7 @@ ags_gui_thread_animation_prepare(GSource *source,
 gboolean
 ags_gui_thread_animation_check(GSource *source)
 {
-  AgsXorgApplicationContext *xorg_application_context;
+  AgsApplicationContext *application_context;
 
   AgsGuiThread *gui_thread;
   
@@ -1239,8 +1239,8 @@ ags_gui_thread_animation_check(GSource *source)
 
   guint nth;
 
-  xorg_application_context = ags_application_context_get_instance();
-  main_loop = AGS_APPLICATION_CONTEXT(xorg_application_context)->main_loop;
+  application_context = ags_application_context_get_instance();
+  main_loop = AGS_APPLICATION_CONTEXT(application_context)->main_loop;
   
   gui_thread = ags_thread_find_type(main_loop,
 				    AGS_TYPE_GUI_THREAD);
@@ -1254,7 +1254,7 @@ ags_gui_thread_animation_check(GSource *source)
   pthread_mutex_unlock(log->mutex);
 
   if(nth > gui_thread->nth_message ||
-     !g_atomic_int_get(&(xorg_application_context->show_animation))){
+     !ags_ui_provider_get_show_animation(AGS_UI_PROVIDER(application_context))){
     return(TRUE);
   }else{
     return(FALSE);
@@ -1266,7 +1266,7 @@ ags_gui_thread_animation_dispatch(GSource *source,
 				  GSourceFunc callback,
 				  gpointer user_data)
 {
-  AgsXorgApplicationContext *xorg_application_context;
+  AgsApplicationContext *application_context;
 
   static GtkWindow *window = NULL;
   static GtkWidget *widget;
@@ -1278,8 +1278,8 @@ ags_gui_thread_animation_dispatch(GSource *source,
   AgsThread *main_loop;
   AgsTaskThread *task_thread;
 
-  xorg_application_context = ags_application_context_get_instance();
-  main_loop = AGS_APPLICATION_CONTEXT(xorg_application_context)->main_loop;
+  application_context = ags_application_context_get_instance();
+  main_loop = AGS_APPLICATION_CONTEXT(application_context)->main_loop;
   
   gui_thread = ags_thread_find_type(main_loop,
 				    AGS_TYPE_GUI_THREAD);
@@ -1312,13 +1312,13 @@ ags_gui_thread_animation_dispatch(GSource *source,
   g_main_context_iteration(main_context,
   			   FALSE);
   
-  if(g_atomic_int_get(&(xorg_application_context->show_animation))){
+  if(ags_ui_provider_get_show_animation(AGS_UI_PROVIDER(application_context))){
     return(G_SOURCE_CONTINUE);
   }else{
     gtk_widget_destroy(window);
     window = NULL;
 
-    gtk_widget_show_all(xorg_application_context->window);
+    gtk_widget_show_all(ags_ui_provider_get_window(AGS_UI_PROVIDER(application_context)));
 
     return(G_SOURCE_REMOVE);
   }
@@ -1417,7 +1417,7 @@ ags_gui_thread_sync_task_dispatch(GSource *source,
 
   main_context = gui_thread->main_context;
 
-  if(g_atomic_int_get(&(AGS_XORG_APPLICATION_CONTEXT(application_context)->show_animation)) == TRUE){
+  if(ags_ui_provider_get_show_animation(AGS_UI_PROVIDER(application_context))){
     return(G_SOURCE_CONTINUE);
   }
 
@@ -1738,14 +1738,14 @@ ags_gui_thread_do_animation_callback(GtkWidget *widget, GdkEventExpose *event,
 void
 ags_gui_thread_do_animation(AgsGuiThread *gui_thread)
 {
-  AgsXorgApplicationContext *xorg_application_context;
+  AgsApplicationContext *application_context;
 
   GtkWindow *window;
   GtkWidget *widget;
   
   GMainContext *main_context;
 
-  xorg_application_context = ags_application_context_get_instance();
+  application_context = ags_application_context_get_instance();
 
   main_context = g_main_context_default();
 
@@ -1769,7 +1769,7 @@ ags_gui_thread_do_animation(AgsGuiThread *gui_thread)
 		   G_CALLBACK(ags_gui_thread_do_animation_callback), gui_thread);
   
   /* iterate log messages */
-  while(g_atomic_int_get(&(xorg_application_context->show_animation))){
+  while(ags_ui_provider_get_show_animation(AGS_UI_PROVIDER(application_context))){
     gtk_widget_queue_draw(widget);
 
     gdk_threads_enter();
@@ -1789,7 +1789,7 @@ ags_gui_thread_do_animation(AgsGuiThread *gui_thread)
 void
 ags_gui_thread_do_run(AgsGuiThread *gui_thread)
 {
-  AgsXorgApplicationContext *xorg_application_context;
+  AgsApplicationContext *application_context;
 
   AgsThread *thread;
   AgsTaskThread *task_thread;
@@ -1805,13 +1805,13 @@ ags_gui_thread_do_run(AgsGuiThread *gui_thread)
     4000000,
   };
 
-  xorg_application_context = ags_application_context_get_instance();
+  application_context = ags_application_context_get_instance();
 
   thread = (AgsThread *) gui_thread;
   g_atomic_int_or(&(gui_thread->flags),
 		  AGS_GUI_THREAD_RUNNING);
 
-  task_thread = (AgsThread *) AGS_APPLICATION_CONTEXT(xorg_application_context)->task_thread;
+  task_thread = (AgsThread *) AGS_APPLICATION_CONTEXT(application_context)->task_thread;
 
   main_context = gui_thread->main_context;
 
@@ -1889,8 +1889,8 @@ ags_gui_thread_do_run(AgsGuiThread *gui_thread)
 #endif
   
   /* show animation */
-  g_atomic_int_set(&(xorg_application_context->gui_ready),
-		   TRUE);
+  ags_ui_provider_set_gui_ready(AGS_UI_PROVIDER(application_context),
+				TRUE);
 
   /* gtk+-2.0 main */    
   gtk_main();
diff --git a/ags/audio/ags_acceleration.c b/ags/audio/ags_acceleration.c
index 1052ee5..4ca918b 100644
--- a/ags/audio/ags_acceleration.c
+++ b/ags/audio/ags_acceleration.c
@@ -19,7 +19,7 @@
 
 #include <ags/audio/ags_acceleration.h>
 
-#include <ags/object/ags_connectable.h>
+#include <ags/libags.h>
 
 #include <stdlib.h>
 
@@ -100,6 +100,7 @@ void
 ags_acceleration_class_init(AgsAccelerationClass *acceleration)
 {
   GObjectClass *gobject;
+
   GParamSpec *param_spec;
   
   ags_acceleration_parent_class = g_type_class_peek_parent(acceleration);
diff --git a/ags/audio/ags_audio.c b/ags/audio/ags_audio.c
index a38a42d..cd85d27 100644
--- a/ags/audio/ags_audio.c
+++ b/ags/audio/ags_audio.c
@@ -1,5 +1,5 @@
 /* GSequencer - Advanced GTK Sequencer
- * Copyright (C) 2005-2017 Joël Krähemann
+ * Copyright (C) 2005-2018 Joël Krähemann
  *
  * This file is part of GSequencer.
  *
@@ -25,6 +25,7 @@
 #include <ags/audio/ags_preset.h>
 #include <ags/audio/ags_notation.h>
 #include <ags/audio/ags_automation.h>
+#include <ags/audio/ags_wave.h>
 #include <ags/audio/ags_output.h>
 #include <ags/audio/ags_input.h>
 #include <ags/audio/ags_playback_domain.h>
@@ -131,6 +132,7 @@ enum{
   PROP_PLAYBACK_DOMAIN,
   PROP_NOTATION,
   PROP_AUTOMATION,
+  PROP_WAVE,
   PROP_RECALL_ID,
   PROP_RECYCLING_CONTEXT,
   PROP_RECALL_CONTAINER,
@@ -607,6 +609,21 @@ ags_audio_class_init(AgsAudioClass *audio)
 				  param_spec);
 
   /**
+   * AgsAudio:wave:
+   *
+   * The #AgsWave it contains.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_pointer("wave",
+				    i18n_pspec("containing wave"),
+				    i18n_pspec("The wave it contains"),
+				    G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_WAVE,
+				  param_spec);
+
+  /**
    * AgsAudio:recall-id:
    *
    * The assigned #AgsRecallID.
@@ -966,9 +983,10 @@ ags_audio_init(AgsAudio *audio)
 	       "domain", audio,
 	       NULL);
 
-  /* notation and automation */
+  /* notation, automation and wave */
   audio->notation = NULL;
   audio->automation = NULL;
+  audio->wave = NULL;
 
   /* recycling context */
   audio->recall_id = NULL;
@@ -1086,7 +1104,7 @@ ags_audio_set_property(GObject *gobject,
       buffer_size = g_value_get_uint(value);
 
       ags_audio_set_buffer_size(audio,
-				  buffer_size);
+				buffer_size);
     }
     break;
   case PROP_FORMAT:
@@ -1265,6 +1283,21 @@ ags_audio_set_property(GObject *gobject,
 			       (GObject *) automation);
     }
     break;
+  case PROP_WAVE:
+    {
+      AgsWave *wave;
+
+      wave = (AgsWave *) g_value_get_pointer(value);
+
+      if(wave == NULL ||
+	 g_list_find(audio->wave, wave) != NULL){
+	return;
+      }
+
+      ags_audio_add_wave(audio,
+			 (GObject *) wave);
+    }
+    break;
   case PROP_RECALL_ID:
     {
       AgsRecallID *recall_id;
@@ -1484,6 +1517,11 @@ ags_audio_get_property(GObject *gobject,
       g_value_set_pointer(value, g_list_copy(audio->automation));
     }
     break;
+  case PROP_WAVE:
+    {
+      g_value_set_pointer(value, g_list_copy(audio->wave));
+    }
+    break;
   case PROP_RECALL_ID:
     {
       g_value_set_pointer(value, g_list_copy(audio->recall_id));
@@ -1624,6 +1662,24 @@ ags_audio_dispose(GObject *gobject)
     audio->automation = NULL;
   }
 
+  /* wave */
+  if(audio->wave != NULL){
+    list = audio->wave;
+
+    while(list != NULL){
+      list_next = list->next;
+      
+      g_object_run_dispose(list->data);
+
+      list = list_next;
+    }
+  
+    g_list_free_full(audio->wave,
+		     g_object_unref);
+
+    audio->wave = NULL;
+  }
+
   /* recall id */
   if(audio->recall_id != NULL){
     list = audio->recall_id;
@@ -1866,6 +1922,22 @@ ags_audio_finalize(GObject *gobject)
     g_list_free_full(audio->automation,
 		     g_object_unref);
   }
+
+  /* wave */
+  if(audio->wave != NULL){
+    list = audio->wave;
+
+    while(list != NULL){
+      g_object_set(list->data,
+		   "audio", NULL,
+		   NULL);
+
+      list = list->next;
+    }
+
+    g_list_free_full(audio->wave,
+		     g_object_unref);
+  }
   
   /* recall id */
   if(audio->recall_id != NULL){
@@ -2623,6 +2695,8 @@ ags_audio_real_set_audio_channels(AgsAudio *audio,
   auto void ags_audio_set_audio_channels_grow_notation();
   auto void ags_audio_set_audio_channels_shrink_notation();
   auto void ags_audio_set_audio_channels_shrink_automation();
+  auto void ags_audio_set_audio_channels_grow_wave();
+  auto void ags_audio_set_audio_channels_shrink_wave();
   
   void ags_audio_set_audio_channels_init_parameters(GType type){
     if(type == AGS_TYPE_OUTPUT){
@@ -3010,6 +3084,56 @@ ags_audio_real_set_audio_channels(AgsAudio *audio,
       automation = automation_next;
     }
   }
+
+  void ags_audio_set_audio_channels_grow_wave(){
+    GList *list;
+    guint i;
+
+    i = audio->audio_channels;
+
+#ifdef AGS_DEBUG
+    g_message("ags_audio_set_audio_channels_grow_wave\n");
+#endif
+
+    if(audio->audio_channels == 0){
+      audio->wave =
+	list = g_list_alloc();
+      goto ags_audio_set_audio_channels_grow_wave0;
+    }else{
+      list = g_list_nth(audio->wave, audio->audio_channels - 1);
+    }
+
+    for(; i < audio_channels; i++){
+      list->next = g_list_alloc();
+      list->next->prev = list;
+      list = list->next;
+
+    ags_audio_set_audio_channels_grow_wave0:
+      list->data = (gpointer) ags_wave_new((GObject *) audio,
+					   i);
+    } 
+  }
+  
+  void ags_audio_set_audio_channels_shrink_wave(){
+    GList *list, *list_next;
+
+    list = g_list_nth(audio->wave, audio_channels);
+
+    if(audio_channels == 0){
+      audio->wave = NULL;
+    }else{
+      list->prev->next = NULL;
+    }
+
+    while(list != NULL){
+      list_next = list->next;
+
+      g_object_unref((GObject *) list->data);
+      g_list_free1(list);
+
+      list = list_next;
+    }
+  }
   
   /* entry point */
   mutex_manager = ags_mutex_manager_get_instance();
@@ -3027,6 +3151,10 @@ ags_audio_real_set_audio_channels(AgsAudio *audio,
       ags_audio_set_audio_channels_grow_notation();
     }
 
+    if((AGS_AUDIO_HAS_WAVE & (audio->flags)) != 0){
+      ags_audio_set_audio_channels_grow_wave();
+    }
+
     if(audio->input_pads > 0 &&
        (AGS_AUDIO_NO_INPUT & (audio->flags)) == 0){
       ags_audio_set_audio_channels_init_parameters(AGS_TYPE_INPUT);
@@ -3068,8 +3196,13 @@ ags_audio_real_set_audio_channels(AgsAudio *audio,
     /* shrink audio channels */
     ags_audio_set_audio_channels_shrink_automation();
     
-    if((AGS_AUDIO_HAS_NOTATION & audio->flags) != 0)
+    if((AGS_AUDIO_HAS_NOTATION & audio->flags) != 0){
       ags_audio_set_audio_channels_shrink_notation();
+    }
+
+    if((AGS_AUDIO_HAS_WAVE & audio->flags) != 0){
+      ags_audio_set_audio_channels_shrink_wave();
+    }
 
     if(audio_channels == 0){
       ags_audio_set_audio_channels_shrink_zero();
@@ -3229,6 +3362,8 @@ ags_audio_real_set_pads(AgsAudio *audio,
   auto void ags_audio_set_pads_add_notes();
   auto void ags_audio_set_pads_remove_notes();
   auto void ags_audio_set_pads_shrink_automation();
+  auto void ags_audio_set_pads_alloc_wave();
+  auto void ags_audio_set_pads_free_wave();
   
   void ags_audio_set_pads_init_parameters(){
     alloc_recycling = FALSE;
@@ -3575,6 +3710,55 @@ ags_audio_real_set_pads(AgsAudio *audio,
       automation = automation_next;
     }
   }
+
+  void ags_audio_set_pads_alloc_wave(){
+    GList *list;
+    
+    guint i;
+
+#ifdef AGS_DEBUG
+    g_message("ags_audio_set_pads_alloc_wave\n");
+#endif
+
+    if(audio->audio_channels > 0){
+      audio->wave =
+	list = g_list_alloc();
+      i = 0;
+      goto ags_audio_set_pads_alloc_wave0;
+    }else{
+      return;
+    }
+
+    for(; i < audio->audio_channels; i++){
+      list->next = g_list_alloc();
+      list->next->prev = list;
+      list = list->next;
+    ags_audio_set_pads_alloc_wave0:
+
+      list->data = (gpointer) ags_wave_new((GObject *) audio,
+					   i);
+    }
+  }
+
+  void ags_audio_set_pads_free_wave(){
+    GList *list, *list_next;
+
+    if(audio->audio_channels > 0){
+      list = audio->wave;
+      audio->wave = NULL;
+    }else{
+      return;
+    }
+
+    while(list != NULL){
+      list_next = list->next;
+
+      g_object_unref(G_OBJECT(list->data));
+      g_list_free1(list);
+
+      list = list_next;
+    }
+  }
   
   /* entry point */
   ags_audio_set_pads_init_parameters();
@@ -3607,6 +3791,10 @@ ags_audio_real_set_pads(AgsAudio *audio,
 	if((AGS_AUDIO_NOTATION_DEFAULT & (audio->flags)) == 0){
 	  ags_audio_set_pads_alloc_notation();
 	}
+
+	if((AGS_AUDIO_WAVE_DEFAULT & (audio->flags)) == 0){
+	  ags_audio_set_pads_alloc_wave();
+	}
       }
 
       if((AGS_AUDIO_NO_OUTPUT & (audio->flags)) == 0){
@@ -3640,6 +3828,11 @@ ags_audio_real_set_pads(AgsAudio *audio,
 	  ags_audio_set_pads_free_notation();
 	}
 
+	if((AGS_AUDIO_HAS_WAVE & (audio->flags)) != 0 &&
+	   audio->wave != NULL){
+	  ags_audio_set_pads_free_wave();
+	}
+
 	channel = audio->output;
       
 	/* unlink and remove */
@@ -3725,6 +3918,10 @@ ags_audio_real_set_pads(AgsAudio *audio,
 	if((AGS_AUDIO_NOTATION_DEFAULT & (audio->flags)) != 0){
 	  ags_audio_set_pads_alloc_notation();
 	}
+
+	if((AGS_AUDIO_WAVE_DEFAULT & (audio->flags)) != 0){
+	  ags_audio_set_pads_alloc_wave();
+	}
       }
 
       /* grow channels */
@@ -4362,6 +4559,80 @@ ags_audio_remove_automation(AgsAudio *audio, GObject *automation)
 }
 
 /**
+ * ags_audio_add_wave:
+ * @audio: the #AgsAudio
+ * @wave: the #AgsRecallID
+ *
+ * Adds a recall id.
+ *
+ * Since: 1.4.0
+ */
+void
+ags_audio_add_wave(AgsAudio *audio, GObject *wave)
+{
+  AgsMutexManager *mutex_manager;
+
+  pthread_mutex_t *application_mutex;
+  pthread_mutex_t *mutex;
+
+  /* lookup mutex */
+  mutex_manager = ags_mutex_manager_get_instance();
+  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
+
+  pthread_mutex_lock(application_mutex);
+
+  mutex = ags_mutex_manager_lookup(mutex_manager,
+				   (GObject *) audio);
+  
+  pthread_mutex_unlock(application_mutex);
+
+  /* add recall id */
+  pthread_mutex_lock(mutex);
+
+  g_object_ref(wave);
+  audio->wave = g_list_prepend(audio->wave, wave);
+  
+  pthread_mutex_unlock(mutex);
+}
+
+/**
+ * ags_audio_remove_wave:
+ * @audio: the #AgsAudio
+ * @wave: the #AgsRecallID
+ *
+ * Removes a recall id.
+ *
+ * Since: 1.4.0
+ */
+void
+ags_audio_remove_wave(AgsAudio *audio, GObject *wave)
+{
+  AgsMutexManager *mutex_manager;
+
+  pthread_mutex_t *application_mutex;
+  pthread_mutex_t *mutex;
+
+  /* lookup mutex */
+  mutex_manager = ags_mutex_manager_get_instance();
+  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
+
+  pthread_mutex_lock(application_mutex);
+
+  mutex = ags_mutex_manager_lookup(mutex_manager,
+				   (GObject *) audio);
+  
+  pthread_mutex_unlock(application_mutex);
+
+  /* remove recall id */
+  pthread_mutex_lock(mutex);
+
+  audio->wave = g_list_remove(audio->wave, wave);
+  g_object_unref(wave);
+  
+  pthread_mutex_unlock(mutex);
+}
+
+/**
  * ags_audio_add_recall_id:
  * @audio: the #AgsAudio
  * @recall_id: the #AgsRecallID
diff --git a/ags/audio/ags_audio.h b/ags/audio/ags_audio.h
index 2bd5d59..c34f5a4 100644
--- a/ags/audio/ags_audio.h
+++ b/ags/audio/ags_audio.h
@@ -1,5 +1,5 @@
 /* GSequencer - Advanced GTK Sequencer
- * Copyright (C) 2005-2017 Joël Krähemann
+ * Copyright (C) 2005-2018 Joël Krähemann
  *
  * This file is part of GSequencer.
  *
@@ -58,6 +58,8 @@ typedef struct _AgsAudioClass AgsAudioClass;
  * @AGS_AUDIO_NO_INPUT: no input provided
  * @AGS_AUDIO_SKIP_OUTPUT: skip output as processing audio data
  * @AGS_AUDIO_SKIP_INPUT: skip input as processing audio data
+ * @AGS_AUDIO_HAS_WAVE: has wave
+ * @AGS_AUDIO_WAVE_DEFAULT: wave default mapped on input channels
  *
  * Enum values to control the behavior or indicate internal state of #AgsAudio by
  * enable/disable as flags.
@@ -81,6 +83,8 @@ typedef enum{
   AGS_AUDIO_NO_INPUT                    = 1 << 15,
   AGS_AUDIO_SKIP_OUTPUT                 = 1 << 16,
   AGS_AUDIO_SKIP_INPUT                  = 1 << 17,
+  AGS_AUDIO_HAS_WAVE                    = 1 << 18,
+  AGS_AUDIO_WAVE_DEFAULT                = 1 << 19,
 }AgsAudioFlags;
 
 struct _AgsAudio
@@ -130,6 +134,7 @@ struct _AgsAudio
   
   GList *notation;
   GList *automation;
+  GList *wave;
   
   GList *recall_id;
   GList *recycling_context;
@@ -195,7 +200,7 @@ void ags_audio_remove_preset(AgsAudio *audio,
 			     GObject *preset);
 
 void ags_audio_add_notation(AgsAudio *audio,
-			      GObject *notation);
+			    GObject *notation);
 void ags_audio_remove_notation(AgsAudio *audio,
 			       GObject *notation);
 
@@ -204,6 +209,11 @@ void ags_audio_add_automation(AgsAudio *audio,
 void ags_audio_remove_automation(AgsAudio *audio,
 				 GObject *automation);
 
+void ags_audio_add_wave(AgsAudio *audio,
+			GObject *wave);
+void ags_audio_remove_wave(AgsAudio *audio,
+			   GObject *wave);
+
 void ags_audio_add_recall_id(AgsAudio *audio, GObject *recall_id);
 void ags_audio_remove_recall_id(AgsAudio *audio, GObject *recall_id);
 
diff --git a/ags/audio/ags_audio_buffer_util.h b/ags/audio/ags_audio_buffer_util.h
index fe9bf41..d478b6a 100644
--- a/ags/audio/ags_audio_buffer_util.h
+++ b/ags/audio/ags_audio_buffer_util.h
@@ -1,5 +1,5 @@
 /* GSequencer - Advanced GTK Sequencer
- * Copyright (C) 2016 Joël Krähemann
+ * Copyright (C) 2005-2018 Joël Krähemann
  *
  * This file is part of GSequencer.
  *
diff --git a/ags/audio/ags_audio_signal.c b/ags/audio/ags_audio_signal.c
index 4c5c0cc..22119e5 100644
--- a/ags/audio/ags_audio_signal.c
+++ b/ags/audio/ags_audio_signal.c
@@ -19,18 +19,15 @@
 
 #include <ags/audio/ags_audio_signal.h>
 
-#include <ags/object/ags_config.h>
-#include <ags/object/ags_marshal.h>
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_soundcard.h>
+#include <ags/libags.h>
 
 #include <ags/audio/ags_recycling.h>
 #include <ags/audio/ags_recall_id.h>
 #include <ags/audio/ags_audio_buffer_util.h>
+#include <ags/audio/ags_note.h>
 
 #include <stdint.h>
-//TODO:JK: do vector optimization
-//#include <emmintrin.h>
+
 #include <stdlib.h>
 #include <math.h>
 #include <string.h>
@@ -54,6 +51,10 @@ void ags_audio_signal_dispose(GObject *gobject);
 void ags_audio_signal_finalize(GObject *gobject);
 
 void ags_audio_signal_real_realloc_buffer_size(AgsAudioSignal *audio_signal, guint buffer_size);
+void ags_audio_signal_real_add_note(AgsAudioSignal *audio_signal,
+				    GObject *note);
+void ags_audio_signal_real_remove_note(AgsAudioSignal *audio_signal,
+				       GObject *note);
 
 /**
  * SECTION:ags_audio_signal
@@ -91,6 +92,8 @@ enum{
 
 enum{
   REALLOC_BUFFER_SIZE,
+  ADD_NOTE,
+  REMOVE_NOTE,
   LAST_SIGNAL,
 };
 
@@ -470,11 +473,10 @@ ags_audio_signal_class_init(AgsAudioSignalClass *audio_signal)
    * 
    * Since: 1.0.0
    */
-  param_spec = g_param_spec_object("note",
-				   i18n_pspec("assigned note"),
-				   i18n_pspec("The note it is assigned with"),
-				   G_TYPE_OBJECT,
-				   G_PARAM_READABLE | G_PARAM_WRITABLE);
+  param_spec = g_param_spec_pointer("note",
+				    i18n_pspec("assigned note"),
+				    i18n_pspec("The note it is assigned with"),
+				    G_PARAM_READABLE | G_PARAM_WRITABLE);
   g_object_class_install_property(gobject,
 				  PROP_NOTE,
 				  param_spec);
@@ -482,6 +484,9 @@ ags_audio_signal_class_init(AgsAudioSignalClass *audio_signal)
   /* AgsAudioSignalClass */
   audio_signal->realloc_buffer_size = ags_audio_signal_real_realloc_buffer_size;
 
+  audio_signal->add_note = ags_audio_signal_real_add_note;
+  audio_signal->remove_note = ags_audio_signal_real_remove_note;
+  
   /* signals */
   /**
    * AgsAudioSignal::realloc-buffer-size:
@@ -489,6 +494,8 @@ ags_audio_signal_class_init(AgsAudioSignalClass *audio_signal)
    * @buffer_size: new buffer size
    *
    * The ::reallloc-buffer-size signal is invoked to notify modified buffer size.
+   * 
+   * Since: 1.0.0
    */
   audio_signal_signals[REALLOC_BUFFER_SIZE] =
     g_signal_new("realloc-buffer-size",
@@ -499,6 +506,44 @@ ags_audio_signal_class_init(AgsAudioSignalClass *audio_signal)
 		 g_cclosure_marshal_VOID__UINT,
 		 G_TYPE_NONE, 1,
 		 G_TYPE_UINT);
+
+  /**
+   * AgsAudioSignal::add-note:
+   * @audio_signal: the #AgsAudioSignal
+   * @note: the #AgsNote
+   *
+   * The ::add-note signal notifies about adding @note.
+   * 
+   * Since: 1.4.0
+   */
+  audio_signal_signals[ADD_NOTE] =
+    g_signal_new("add-note",
+		 G_TYPE_FROM_CLASS(audio_signal),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsAudioSignalClass, add_note),
+		 NULL, NULL,
+		 g_cclosure_marshal_VOID__OBJECT,
+		 G_TYPE_NONE, 1,
+		 G_TYPE_OBJECT);
+
+  /**
+   * AgsAudioSignal::remove-note:
+   * @audio_signal: the #AgsAudioSignal
+   * @note: the #AgsNote
+   *
+   * The ::remove-note signal notifies about removing @note.
+   * 
+   * Since: 1.4.0
+   */
+  audio_signal_signals[REMOVE_NOTE] =
+    g_signal_new("remove-note",
+		 G_TYPE_FROM_CLASS(audio_signal),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsAudioSignalClass, remove_note),
+		 NULL, NULL,
+		 g_cclosure_marshal_VOID__OBJECT,
+		 G_TYPE_NONE, 1,
+		 G_TYPE_OBJECT);
 }
 
 void
@@ -827,18 +872,14 @@ ags_audio_signal_set_property(GObject *gobject,
     {
       GObject *note;
 
-      note = g_value_get_object(value);
+      note = g_value_get_pointer(value);
 
-      if(audio_signal->note == note)
+      if(g_list_find(audio_signal->note, note) != NULL){
 	return;
+      }
 
-      if(audio_signal->note != NULL)
-	g_object_unref(audio_signal->note);
-
-      if(note != NULL)
-	g_object_ref(note);
-
-      audio_signal->note = note;
+      ags_audio_signal_add_note(audio_signal,
+				note);
     }
     break;
   default:
@@ -949,7 +990,8 @@ ags_audio_signal_get_property(GObject *gobject,
     break;
   case PROP_NOTE:
     {
-      g_value_set_object(value, audio_signal->note);
+      g_value_set_pointer(value,
+			  g_list_copy(audio_signal->note));
     }
     break;
   default:
@@ -1146,6 +1188,17 @@ ags_stream_alloc(guint buffer_size,
   return(buffer);
 }
 
+/**
+ * ags_stream_free:
+ * @buffer_size: the buffer size
+ * @format: the format
+ *
+ * Frees an audio buffer.
+ *
+ * Returns: the audio data array
+ *
+ * Since: 1.0.0
+ */
 void
 ags_stream_free(signed short *buffer)
 {
@@ -1181,6 +1234,13 @@ ags_audio_signal_set_buffer_size(AgsAudioSignal *audio_signal, guint buffer_size
 {
   GList *stream;
 
+  guint old_buffer_size;
+  guint word_size;
+  
+  old_buffer_size = audio_signal->buffer_size;
+
+  audio_signal->buffer_size = buffer_size;
+
   stream = audio_signal->stream_beginning;
 
   while(stream != NULL){
@@ -1189,40 +1249,47 @@ ags_audio_signal_set_buffer_size(AgsAudioSignal *audio_signal, guint buffer_size
       {
 	stream->data = (signed char *) realloc(stream->data,
 					       buffer_size * sizeof(signed char));
+	word_size = sizeof(signed char);
       }
       break;
     case AGS_SOUNDCARD_SIGNED_16_BIT:
       {
-	stream->data = (signed char *) realloc(stream->data,
-					       buffer_size * sizeof(signed short));
+	stream->data = (signed short *) realloc(stream->data,
+						buffer_size * sizeof(signed short));
+	word_size = sizeof(signed short);
       }
       break;
     case AGS_SOUNDCARD_SIGNED_24_BIT:
       {
-	stream->data = (signed char *) realloc(stream->data,
+	stream->data = (signed long *) realloc(stream->data,
 					       buffer_size * sizeof(signed long));
+	word_size = sizeof(signed long);
       }
       break;
     case AGS_SOUNDCARD_SIGNED_32_BIT:
       {
-	stream->data = (signed char *) realloc(stream->data,
+	stream->data = (signed long *) realloc(stream->data,
 					       buffer_size * sizeof(signed long));
+	word_size = sizeof(signed long);
       }
       break;
     case AGS_SOUNDCARD_SIGNED_64_BIT:
       {
-	stream->data = (signed char *) realloc(stream->data,
-					       buffer_size * sizeof(signed long long));
+	stream->data = (signed long long *) realloc(stream->data,
+						    buffer_size * sizeof(signed long long));
+	word_size = sizeof(signed long long);
       }
       break;
     default:
       g_warning("ags_audio_signal_set_buffer_size() - unsupported format");
     }
+
+    if(old_buffer_size < buffer_size){
+      memset(stream->data + old_buffer_size, 0, (buffer_size - old_buffer_size) * word_size);
+    }
     
     stream = stream->next;
   }
-
-  audio_signal->buffer_size = buffer_size;
 }
 
 /**
@@ -1239,43 +1306,26 @@ ags_audio_signal_set_format(AgsAudioSignal *audio_signal, guint format)
 {
   GList *stream;
 
+  void *data;
+
+  guint copy_mode;
+
   stream = audio_signal->stream_beginning;
 
   while(stream != NULL){
-    switch(format){
-    case AGS_SOUNDCARD_SIGNED_8_BIT:
-      {
-	stream->data = (signed char *) realloc(stream->data,
-					       audio_signal->buffer_size * sizeof(signed char));
-      }
-      break;
-    case AGS_SOUNDCARD_SIGNED_16_BIT:
-      {
-	stream->data = (signed char *) realloc(stream->data,
-					       audio_signal->buffer_size * sizeof(signed short));
-      }
-      break;
-    case AGS_SOUNDCARD_SIGNED_24_BIT:
-      {
-	stream->data = (signed char *) realloc(stream->data,
-					       audio_signal->buffer_size * sizeof(signed long));
-      }
-      break;
-    case AGS_SOUNDCARD_SIGNED_32_BIT:
-      {
-	stream->data = (signed char *) realloc(stream->data,
-					       audio_signal->buffer_size * sizeof(signed long));
-      }
-      break;
-    case AGS_SOUNDCARD_SIGNED_64_BIT:
-      {
-	stream->data = (signed char *) realloc(stream->data,
-					       audio_signal->buffer_size * sizeof(signed long long));
-      }
-      break;
-    default:
-      g_warning("ags_audio_signal_set_format() - unsupported format");
-    }
+    data = ags_stream_alloc(audio_signal->buffer_size,
+			    format);
+    
+    copy_mode = ags_audio_buffer_util_get_copy_mode(format,
+						    audio_signal->format);
+    
+    ags_audio_buffer_util_copy_buffer_to_buffer(data, 1, 0,
+						stream->data, 1, 0,
+						audio_signal->buffer_size, copy_mode);
+
+    free(stream->data);
+
+    stream->data = data;
     
     stream = stream->next;
   }
@@ -1638,6 +1688,76 @@ ags_audio_signal_duplicate_stream(AgsAudioSignal *audio_signal,
   }
 }
 
+void
+ags_audio_signal_real_add_note(AgsAudioSignal *audio_signal,
+			       GObject *note)
+{
+  if(!(AGS_IS_NOTE(note))){
+    return;
+  }
+  
+  g_object_ref(note);  
+  audio_signal->note = g_list_prepend(audio_signal->note,
+				      note);
+}
+
+/**
+ * ags_audio_signal_add_note:
+ * @audio_signal: the #AgsAudioSignal
+ * @note: the #AgsNote
+ * 
+ * Add note to @audio_signal.
+ * 
+ * Since: 1.4.0
+ */
+void
+ags_audio_signal_add_note(AgsAudioSignal *audio_signal,
+			  GObject *note)
+{
+  g_return_if_fail(AGS_IS_AUDIO_SIGNAL(audio_signal));
+  g_object_ref(G_OBJECT(audio_signal));
+  g_signal_emit(G_OBJECT(audio_signal),
+		audio_signal_signals[ADD_NOTE], 0,
+		note);
+  g_object_unref(G_OBJECT(audio_signal));
+}
+
+void
+ags_audio_signal_real_remove_note(AgsAudioSignal *audio_signal,
+				  GObject *note)
+{
+  if(!(AGS_IS_NOTE(note))){
+    return;
+  }
+  
+  if(g_list_find(audio_signal->note, note) != NULL){
+    audio_signal->note = g_list_remove(audio_signal->note,
+				       note);
+    g_object_unref(note);  
+  }
+}
+
+/**
+ * ags_audio_signal_remove_note:
+ * @audio_signal: the #AgsAudioSignal
+ * @note: the #AgsNote
+ * 
+ * Remove note from @audio_signal.
+ * 
+ * Since: 1.4.0
+ */
+void
+ags_audio_signal_remove_note(AgsAudioSignal *audio_signal,
+			     GObject *note)
+{
+  g_return_if_fail(AGS_IS_AUDIO_SIGNAL(audio_signal));
+  g_object_ref(G_OBJECT(audio_signal));
+  g_signal_emit(G_OBJECT(audio_signal),
+		audio_signal_signals[REMOVE_NOTE], 0,
+		note);
+  g_object_unref(G_OBJECT(audio_signal));
+}
+
 /**
  * ags_audio_signal_get_template:
  * @audio_signal: a #GList containing #AgsAudioSignal
diff --git a/ags/audio/ags_audio_signal.h b/ags/audio/ags_audio_signal.h
index 3fbfacb8..eefee52 100644
--- a/ags/audio/ags_audio_signal.h
+++ b/ags/audio/ags_audio_signal.h
@@ -81,7 +81,7 @@ struct _AgsAudioSignal
   GList *stream_current;
   GList *stream_end;
 
-  GObject *note;
+  GList *note;
 };
 
 struct _AgsAudioSignalClass
@@ -90,6 +90,11 @@ struct _AgsAudioSignalClass
 
   void (*reset_format)(AgsAudioSignal *audio_signal, guint format);
   void (*realloc_buffer_size)(AgsAudioSignal *audio_signal, guint buffer_size);
+
+  void (*add_note)(AgsAudioSignal *audio_signal,
+		   GObject *note);
+  void (*remove_note)(AgsAudioSignal *audio_signal,
+		      GObject *note);
 };
 
 GType ags_audio_signal_get_type();
@@ -113,6 +118,11 @@ void ags_audio_signal_realloc_buffer_size(AgsAudioSignal *audio_signal, guint bu
 void ags_audio_signal_duplicate_stream(AgsAudioSignal *audio_signal,
 				       AgsAudioSignal *template);
 
+void ags_audio_signal_add_note(AgsAudioSignal *audio_signal,
+			       GObject *note);
+void ags_audio_signal_remove_note(AgsAudioSignal *audio_signal,
+				  GObject *note);
+
 //TODO:JK: rename these functions name it rather find than get
 AgsAudioSignal* ags_audio_signal_get_template(GList *audio_signal);
 GList* ags_audio_signal_get_stream_current(GList *audio_signal,
diff --git a/ags/audio/ags_automation.c b/ags/audio/ags_automation.c
index 33e80ce..7397482 100644
--- a/ags/audio/ags_automation.c
+++ b/ags/audio/ags_automation.c
@@ -1690,6 +1690,8 @@ ags_automation_insert_native_scale_from_clipboard(AgsAutomation *automation,
 						  gboolean from_y_offset, guint y_offset,
 						  gboolean match_line, gboolean no_duplicates)
 {
+  gboolean match_timestamp;
+  
   auto void ags_automation_insert_from_clipboard_version_0_4_3();
   
   void ags_automation_insert_from_clipboard_version_0_4_3()
@@ -1833,25 +1835,29 @@ ags_automation_insert_native_scale_from_clipboard(AgsAutomation *automation,
 	}
 
 	/* check duplicate */
-	if(ags_automation_find_point(automation,
+	if(no_duplicates &&
+	   ags_automation_find_point(automation,
 				     x_val, y_val,
 				     FALSE) != NULL){
 	  continue;
 	}
 	
 	/* add acceleration */
-	acceleration = ags_acceleration_new();
-
-	acceleration->x = x_val;
-	acceleration->y = y_val;
+	if(!match_timestamp ||
+	   x_val < automation->timestamp->timer.ags_offset.offset + AGS_AUTOMATION_DEFAULT_OFFSET){
+	  acceleration = ags_acceleration_new();
+	  
+	  acceleration->x = x_val;
+	  acceleration->y = y_val;
 
 #ifdef AGS_DEBUG
-	g_message("adding acceleration at: [%u|%f]\n", x_val, y_val);
+	  g_message("adding acceleration at: [%u|%f]\n", x_val, y_val);
 #endif
-	
-	ags_automation_add_acceleration(automation,
-					acceleration,
-					FALSE);
+	  
+	  ags_automation_add_acceleration(automation,
+					  acceleration,
+					  FALSE);
+	}
       }
     }
   }
@@ -1860,9 +1866,13 @@ ags_automation_insert_native_scale_from_clipboard(AgsAutomation *automation,
     return;
   }  
 
+  match_timestamp = TRUE;
+  
   if(!xmlStrncmp("0.4.3", version, 6)){
     ags_automation_insert_from_clipboard_version_0_4_3();
   }else if(!xmlStrncmp("1.3.0", version, 6)){
+    match_timestamp = TRUE;
+    
     if(match_line &&
        automation->line != g_ascii_strtoull(xmlGetProp(root_node,
 						       "line"),
diff --git a/ags/audio/ags_buffer.c b/ags/audio/ags_buffer.c
new file mode 100644
index 0000000..7add27e
--- /dev/null
+++ b/ags/audio/ags_buffer.c
@@ -0,0 +1,586 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2018 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/ags_buffer.h>
+
+#include <ags/libags.h>
+
+#include <ags/audio/ags_audio_signal.h>
+#include <ags/audio/ags_audio_buffer_util.h>
+
+#include <ags/i18n.h>
+
+#include <stdlib.h>
+
+void ags_buffer_class_init(AgsBufferClass *buffer);
+void ags_buffer_connectable_interface_init(AgsConnectableInterface *connectable);
+void ags_buffer_init(AgsBuffer *buffer);
+void ags_buffer_set_property(GObject *gobject,
+			     guint prop_id,
+			     const GValue *value,
+			     GParamSpec *param_spec);
+void ags_buffer_get_property(GObject *gobject,
+			     guint prop_id,
+			     GValue *value,
+			     GParamSpec *param_spec);
+void ags_buffer_connect(AgsConnectable *connectable);
+void ags_buffer_disconnect(AgsConnectable *connectable);
+void ags_buffer_finalize(GObject *gobject);
+
+/**
+ * SECTION:ags_buffer
+ * @short_description: Buffer class.
+ * @title: AgsBuffer
+ * @section_id:
+ * @include: ags/audio/ags_buffer.h
+ *
+ * #AgsBuffer represents a tone.
+ */
+
+static gpointer ags_buffer_parent_class = NULL;
+
+enum{
+  PROP_0,
+  PROP_X,
+  PROP_SELECTION_X0,
+  PROP_SELECTION_X1,
+  PROP_SAMPLERATE,
+  PROP_BUFFER_SIZE,
+  PROP_FORMAT,
+  PROP_DATA,
+};
+
+GType
+ags_buffer_get_type()
+{
+  static GType ags_type_buffer = 0;
+
+  if(!ags_type_buffer){
+    static const GTypeInfo ags_buffer_info = {
+      sizeof(AgsBufferClass),
+      NULL,
+      NULL,
+      (GClassInitFunc) ags_buffer_class_init,
+      NULL,
+      NULL,
+      sizeof(AgsBuffer),
+      0,
+      (GInstanceInitFunc) ags_buffer_init,
+    };
+
+    static const GInterfaceInfo ags_connectable_interface_info = {
+      (GInterfaceInitFunc) ags_buffer_connectable_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };
+
+    ags_type_buffer = g_type_register_static(G_TYPE_OBJECT,
+					     "AgsBuffer",
+					     &ags_buffer_info,
+					     0);
+    
+    g_type_add_interface_static(ags_type_buffer,
+				AGS_TYPE_CONNECTABLE,
+				&ags_connectable_interface_info);
+  }
+
+  return(ags_type_buffer);
+}
+
+void 
+ags_buffer_class_init(AgsBufferClass *buffer)
+{
+  GObjectClass *gobject;
+
+  GParamSpec *param_spec;
+
+  ags_buffer_parent_class = g_type_class_peek_parent(buffer);
+
+  gobject = (GObjectClass *) buffer;
+
+  gobject->set_property = ags_buffer_set_property;
+  gobject->get_property = ags_buffer_get_property;
+
+  gobject->finalize = ags_buffer_finalize;
+
+  /* properties */
+  /**
+   * AgsBuffer:x:
+   *
+   * Buffer's x offset.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_uint("x",
+				 i18n_pspec("offset x"),
+				 i18n_pspec("The x offset"),
+				 0,
+				 G_MAXUINT,
+				 0,
+				 G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_X,
+				  param_spec);
+
+  /**
+   * AgsBuffer:selection-x0:
+   *
+   * Buffer's selection x0 offset.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_uint("selection-x0",
+				 i18n_pspec("selection offset x0"),
+				 i18n_pspec("The selection's x0 offset"),
+				 0,
+				 G_MAXUINT,
+				 0,
+				 G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_SELECTION_X0,
+				  param_spec);
+
+  /**
+   * AgsBuffer:selection-x1:
+   *
+   * Buffer's selection x1 offset.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_uint("selection-x1",
+				 i18n_pspec("selection offset x1"),
+				 i18n_pspec("The selection's x1 offset"),
+				 0,
+				 G_MAXUINT,
+				 0,
+				 G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_SELECTION_X1,
+				  param_spec);
+
+  /**
+   * AgsBuffer:samplerate:
+   *
+   * Buffer's audio data samplerate.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_uint("samplerate",
+				 i18n_pspec("audio data samplerate"),
+				 i18n_pspec("The samplerate of audio data"),
+				 0,
+				 G_MAXUINT,
+				 AGS_SOUNDCARD_DEFAULT_SAMPLERATE,
+				 G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_SAMPLERATE,
+				  param_spec);
+
+  /**
+   * AgsBuffer:buffer-size:
+   *
+   * Buffer's audio data buffer size.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_uint("buffer-size",
+				 i18n_pspec("audio data's buffer size"),
+				 i18n_pspec("The buffer size of audio data"),
+				 0,
+				 G_MAXUINT,
+				 AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE,
+				 G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_BUFFER_SIZE,
+				  param_spec);
+
+  /**
+   * AgsBuffer:format:
+   *
+   * Buffer's audio data format.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_uint("format",
+				 i18n_pspec("audio data format"),
+				 i18n_pspec("The format of audio data"),
+				 0,
+				 G_MAXUINT,
+				 AGS_SOUNDCARD_DEFAULT_FORMAT,
+				 G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_FORMAT,
+				  param_spec);
+
+  /**
+   * AgsBuffer:data:
+   *
+   * Buffer's audio data.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_pointer("data",
+				    i18n_pspec("audio data"),
+				    i18n_pspec("The audio data"),
+				    G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_DATA,
+				  param_spec);
+}
+
+void
+ags_buffer_connectable_interface_init(AgsConnectableInterface *connectable)
+{
+  connectable->connect = ags_buffer_connect;
+  connectable->disconnect = ags_buffer_disconnect;
+}
+
+void
+ags_buffer_init(AgsBuffer *buffer)
+{  
+  buffer->flags = 0;
+
+  buffer->x = 0;
+
+  buffer->selection_x0 = 0;
+  buffer->selection_x1 = 0;
+
+  buffer->format = AGS_SOUNDCARD_DEFAULT_FORMAT;
+  buffer->buffer_size = AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE;
+
+  buffer->data = ags_stream_alloc(buffer->buffer_size,
+				  buffer->format);
+}
+
+void
+ags_buffer_connect(AgsConnectable *connectable)
+{
+  AgsBuffer *buffer;
+
+  buffer = AGS_BUFFER(connectable);
+
+  if((AGS_BUFFER_CONNECTED & (buffer->flags)) != 0){
+    return;
+  }
+
+  buffer->flags |= AGS_BUFFER_CONNECTED;
+}
+
+void
+ags_buffer_disconnect(AgsConnectable *connectable)
+{
+  AgsBuffer *buffer;
+
+  buffer = AGS_BUFFER(connectable);
+
+  if((AGS_BUFFER_CONNECTED & (buffer->flags)) == 0){
+    return;
+  }
+
+  buffer->flags &= (~AGS_BUFFER_CONNECTED);
+}
+
+void
+ags_buffer_set_property(GObject *gobject,
+			guint prop_id,
+			const GValue *value,
+			GParamSpec *param_spec)
+{
+  AgsBuffer *buffer;
+
+  buffer = AGS_BUFFER(gobject);
+
+  switch(prop_id){
+  case PROP_X:
+    {
+      buffer->x = g_value_get_uint(value);
+    }
+    break;
+  case PROP_SELECTION_X0:
+    {
+      buffer->selection_x0 = g_value_get_uint(value);
+    }
+    break;
+  case PROP_SELECTION_X1:
+    {
+      buffer->selection_x1 = g_value_get_uint(value);
+    }
+    break;
+  case PROP_SAMPLERATE:
+    {
+      guint samplerate;
+      
+      samplerate = g_value_get_uint(value);
+
+      ags_buffer_set_samplerate(buffer,
+				samplerate);
+    }
+    break;
+  case PROP_BUFFER_SIZE:
+    {
+      guint buffer_size;
+      
+      buffer_size = g_value_get_uint(value);
+
+      ags_buffer_set_buffer_size(buffer,
+				 buffer_size);
+    }
+    break;
+  case PROP_FORMAT:
+    {
+      guint format;
+      
+      format = g_value_get_uint(value);
+
+      ags_buffer_set_format(buffer,
+			    format);
+    }
+    break;
+  case PROP_DATA:
+    {
+      buffer->data = g_value_get_pointer(value);
+    }
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
+    break;
+  }
+}
+
+void
+ags_buffer_get_property(GObject *gobject,
+			guint prop_id,
+			GValue *value,
+			GParamSpec *param_spec)
+{
+  AgsBuffer *buffer;
+
+  buffer = AGS_BUFFER(gobject);
+
+  switch(prop_id){
+  case PROP_X:
+    {
+      g_value_set_uint(value,
+		       buffer->x);
+    }
+    break;
+  case PROP_SELECTION_X0:
+    {
+      g_value_set_uint(value,
+		       buffer->selection_x0);
+    }
+    break;
+  case PROP_SELECTION_X1:
+    {
+      g_value_set_uint(value,
+		       buffer->selection_x1);
+    }
+    break;
+  case PROP_SAMPLERATE:
+    {
+      g_value_set_uint(value,
+		       buffer->samplerate);
+    }
+    break;
+  case PROP_BUFFER_SIZE:
+    {
+      g_value_set_uint(value,
+		       buffer->buffer_size);
+    }
+    break;
+  case PROP_FORMAT:
+    {
+      g_value_set_uint(value,
+		       buffer->format);
+    }
+    break;
+  case PROP_DATA:
+    {
+      g_value_set_pointer(value,
+			  buffer->data);
+    }
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
+    break;
+  }
+}
+
+void
+ags_buffer_finalize(GObject *gobject)
+{
+  AgsBuffer *buffer;
+
+  buffer = AGS_BUFFER(gobject);
+
+  if(buffer->data != NULL){
+    free(buffer->data);
+  }
+  
+  /* call parent */
+  G_OBJECT_CLASS(ags_buffer_parent_class)->finalize(gobject);
+}
+
+void
+ags_buffer_set_samplerate(AgsBuffer *buffer,
+			  guint samplerate)
+{
+  buffer->samplerate = samplerate;
+}
+
+void
+ags_buffer_set_buffer_size(AgsBuffer *buffer,
+			   guint buffer_size)
+{
+  guint old_buffer_size;
+  guint word_size;
+  
+  old_buffer_size = buffer->buffer_size;
+  
+  buffer->buffer_size = buffer_size;
+
+  switch(buffer->format){
+  case AGS_SOUNDCARD_SIGNED_8_BIT:
+    {
+      buffer->data = (signed char *) realloc(buffer->data,
+					     buffer_size * sizeof(signed char));
+      word_size = sizeof(signed char);
+    }
+    break;
+  case AGS_SOUNDCARD_SIGNED_16_BIT:
+    {
+      buffer->data = (signed short *) realloc(buffer->data,
+					      buffer_size * sizeof(signed short));
+      word_size = sizeof(signed short);
+    }
+    break;
+  case AGS_SOUNDCARD_SIGNED_24_BIT:
+    {
+      buffer->data = (signed long *) realloc(buffer->data,
+					     buffer_size * sizeof(signed long));
+      //NOTE:JK: The 24-bit linear samples use 32-bit physical space
+      word_size = sizeof(signed long);
+    }
+    break;
+  case AGS_SOUNDCARD_SIGNED_32_BIT:
+    {
+      buffer->data = (signed long *) realloc(buffer->data,
+					     buffer_size * sizeof(signed long));
+      word_size = sizeof(signed long);
+    }
+    break;
+  case AGS_SOUNDCARD_SIGNED_64_BIT:
+    {
+      buffer->data = (signed long long *) realloc(buffer->data,
+						  buffer_size * sizeof(signed long long));
+      word_size = sizeof(signed long long);
+    }
+    break;
+  default:
+    g_warning("ags_buffer_set_buffer_size(): unsupported word size");
+    return(NULL);
+  }
+
+  if(old_buffer_size < buffer_size){
+    memset(buffer->data + old_buffer_size, 0, (buffer_size - old_buffer_size) * word_size);
+  }
+}
+
+void
+ags_buffer_set_format(AgsBuffer *buffer,
+		      guint format)
+{
+  void *data;
+
+  guint copy_mode;
+
+  data = ags_stream_alloc(buffer->buffer_size,
+			  format);
+
+  copy_mode = ags_audio_buffer_util_get_copy_mode(format,
+						  buffer->format);
+  
+  ags_audio_buffer_util_copy_buffer_to_buffer(data, 1, 0,
+					      buffer->data, 1, 0,
+					      buffer->buffer_size, copy_mode);
+
+  free(buffer->data);
+
+  buffer->data = data;
+
+  buffer->format = format;
+}
+
+/**
+ * ags_buffer_sort_func:
+ * @a: an #AgsBuffer
+ * @b: an #AgsBuffer
+ * 
+ * Sort buffers.
+ * 
+ * Returns: 0 if equal, -1 if smaller and 1 if bigger offset
+ *
+ * Since: 1.4.0
+ */
+gint
+ags_buffer_sort_func(gconstpointer a,
+		     gconstpointer b)
+{
+  if(a == NULL || b == NULL){
+    return(0);
+  }
+    
+  if(AGS_BUFFER(a)->x == AGS_BUFFER(b)->x){
+    return(0);
+  }
+
+  if(AGS_BUFFER(a)->x < AGS_BUFFER(b)->x){
+    return(-1);
+  }else{
+    return(1);
+  }  
+}
+
+AgsBuffer*
+ags_buffer_duplicate(AgsBuffer *buffer)
+{
+  //TODO:JK: implement me
+
+  return(NULL);
+}
+
+/**
+ * ags_buffer_new:
+ *
+ * Creates an #AgsBuffer
+ *
+ * Returns: a new #AgsBuffer
+ *
+ * Since: 1.4.0
+ */
+AgsBuffer*
+ags_buffer_new()
+{
+  AgsBuffer *buffer;
+
+  buffer = (AgsBuffer *) g_object_new(AGS_TYPE_BUFFER,
+				      NULL);
+
+  return(buffer);
+}
diff --git a/ags/audio/ags_buffer.h b/ags/audio/ags_buffer.h
new file mode 100644
index 0000000..71eca2d
--- /dev/null
+++ b/ags/audio/ags_buffer.h
@@ -0,0 +1,92 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2018 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_BUFFER_H__
+#define __AGS_BUFFER_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <alsa/asoundlib.h>
+
+#define AGS_TYPE_BUFFER                (ags_buffer_get_type())
+#define AGS_BUFFER(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_BUFFER, AgsBuffer))
+#define AGS_BUFFER_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_BUFFER, AgsBufferClass))
+#define AGS_IS_BUFFER(obj)             (G_TYPE_CHECK_INSTANCE_TYPE((obj), AGS_TYPE_BUFFER))
+#define AGS_IS_BUFFER_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE((class), AGS_TYPE_BUFFER))
+#define AGS_BUFFER_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS((obj), AGS_TYPE_BUFFER, AgsBufferClass))
+
+#define AGS_BUFFER_DEFAULT_TICKS_PER_QUARTER_BUFFER (16.0)
+
+typedef struct _AgsBuffer AgsBuffer;
+typedef struct _AgsBufferClass AgsBufferClass;
+
+/**
+ * AgsBufferFlags:
+ * @AGS_BUFFER_CONNECTED: indicates the buffer was connected by calling #AgsConnectable::connect()
+ * @AGS_BUFFER_IS_SELECTED: is selected
+ *
+ * Enum values to control the behavior or indicate internal state of #AgsBuffer by
+ * enable/disable as flags.
+ */
+typedef enum{
+  AGS_BUFFER_CONNECTED       = 1,
+  AGS_BUFFER_IS_SELECTED     = 1 <<  1,
+}AgsBufferFlags;
+
+struct _AgsBuffer
+{
+  GObject object;
+
+  guint flags;
+
+  guint64 x;
+  
+  guint selection_x0;
+  guint selection_x1;
+
+  guint samplerate;
+  guint buffer_size;
+  guint format;
+  
+  void *data;
+};
+
+struct _AgsBufferClass
+{
+  GObjectClass object;
+};
+
+GType ags_buffer_get_type();
+
+void ags_buffer_set_samplerate(AgsBuffer *buffer,
+			       guint samplerate);
+void ags_buffer_set_buffer_size(AgsBuffer *buffer,
+				guint buffer_size);
+void ags_buffer_set_format(AgsBuffer *buffer,
+			   guint format);
+
+gint ags_buffer_sort_func(gconstpointer a,
+			  gconstpointer b);
+
+AgsBuffer* ags_buffer_duplicate(AgsBuffer *buffer);
+
+AgsBuffer* ags_buffer_new();
+
+#endif /*__AGS_BUFFER_H__*/
diff --git a/ags/audio/ags_channel.c b/ags/audio/ags_channel.c
index 35e91ab..c8d179c 100644
--- a/ags/audio/ags_channel.c
+++ b/ags/audio/ags_channel.c
@@ -3219,6 +3219,8 @@ ags_channel_add_ladspa_effect(AgsChannel *channel,
       
 	ags_recall_run_init_inter(current);
 	ags_recall_run_init_post(current);
+
+	ags_recall_check_rt_stream(current);
       }
       
       /* iterate */
@@ -3314,6 +3316,8 @@ ags_channel_add_ladspa_effect(AgsChannel *channel,
       
 	ags_recall_run_init_inter(current);
 	ags_recall_run_init_post(current);
+
+	ags_recall_check_rt_stream(current);
       }
       
       /* iterate */
@@ -3461,6 +3465,8 @@ ags_channel_add_dssi_effect(AgsChannel *channel,
       
 	ags_recall_run_init_inter(current);
 	ags_recall_run_init_post(current);
+
+	ags_recall_check_rt_stream(current);
       }
       
       /* iterate */
@@ -3556,6 +3562,8 @@ ags_channel_add_dssi_effect(AgsChannel *channel,
       
 	ags_recall_run_init_inter(current);
 	ags_recall_run_init_post(current);
+
+	ags_recall_check_rt_stream(current);
       }
       
       /* iterate */
@@ -3709,6 +3717,8 @@ ags_channel_add_lv2_effect(AgsChannel *channel,
       
 	ags_recall_run_init_inter(current);
 	ags_recall_run_init_post(current);
+
+	ags_recall_check_rt_stream(current);
       }
       
       /* iterate */
@@ -3809,6 +3819,8 @@ ags_channel_add_lv2_effect(AgsChannel *channel,
       
 	ags_recall_run_init_inter(current);
 	ags_recall_run_init_post(current);
+
+	ags_recall_check_rt_stream(current);
       }
       
       /* iterate */
@@ -4666,8 +4678,10 @@ ags_channel_init_recall(AgsChannel *channel, gint stage,
 	recall->flags &= (~AGS_RECALL_REMOVE);
       }else if(stage == 1){
 	ags_recall_run_init_inter(recall);
-      }else{
+      }else if(stage == 2){
 	ags_recall_run_init_post(recall);
+      }else{
+	ags_recall_check_rt_stream(recall);
       }
     }
     
@@ -4733,9 +4747,10 @@ ags_channel_play(AgsChannel *channel,
 
   pthread_mutex_unlock(mutex);
 
-  list = list_start;
   
-  /* run */
+  /* run - automate */
+  list = list_start;
+
   while(list != NULL){
     guint recall_flags;
     
@@ -4745,16 +4760,7 @@ ags_channel_play(AgsChannel *channel,
     
     if(recall == NULL ||
        !AGS_IS_RECALL(recall)){
-      //      if(recall_id->recycling_context->parent != NULL){
-      //	channel->recall = g_list_remove(channel->recall,
-      //					recall);
-      //      }else{
-      //	channel->play = g_list_remove(channel->play,
-      //				      recall);
-      //      }
-
       list = list_next;
-      g_warning("recall == NULL");
       
       continue;
     }
@@ -4764,7 +4770,87 @@ ags_channel_play(AgsChannel *channel,
       if(stage == 0){
 	ags_recall_automate(recall);
       }
+    }
+    
+    list = list_next;
+  }
+
+  /* run - first */
+  list = list_start;
+
+  while(list != NULL){
+    guint recall_flags;
+    
+    list_next = list->next;
+
+    recall = AGS_RECALL(list->data);
+    
+    if(recall == NULL ||
+       !AGS_IS_RECALL(recall)){
+      list = list_next;
+      
+      continue;
+    }
+
+    if(AGS_IS_RECALL_CHANNEL(recall)){
+      list = list_next;
+
+      continue;
+    }
+
+    if(recall->recall_id == NULL ||
+       recall->recall_id->recycling_context != recall_id->recycling_context){
+      list = list_next;
+
+      continue;
+    }
+
+    g_object_ref(recall);
+
+    recall_flags = recall->flags;
+        
+    if((AGS_RECALL_TEMPLATE & (recall_flags)) == 0 &&
+       (AGS_RECALL_RUN_FIRST & (recall_flags)) != 0){
+#ifdef AGS_DEBUG
+      g_message("%s play channel %x:%d @%x -> %x", G_OBJECT_TYPE_NAME(recall), channel, channel->line, recall, recall->recall_id);
+#endif
+
+      if((AGS_RECALL_HIDE & (recall_flags)) == 0){
+	g_object_ref(recall);
+	
+	if(stage == 0){
+	  AGS_RECALL_GET_CLASS(recall)->run_pre(recall);
+	}else if(stage == 1){
+	  AGS_RECALL_GET_CLASS(recall)->run_inter(recall);
+	}else{
+	  AGS_RECALL_GET_CLASS(recall)->run_post(recall);
+	}
+
+	g_object_unref(recall);
+      }
+    }
+
+    list = list_next;
+  }
+  
+  /* run */
+  list = list_start;
+
+  while(list != NULL){
+    guint recall_flags;
+    
+    list_next = list->next;
+
+    recall = AGS_RECALL(list->data);
+    
+    if(recall == NULL ||
+       !AGS_IS_RECALL(recall)){
+      list = list_next;
+      
+      continue;
+    }
 
+    if(AGS_IS_RECALL_CHANNEL(recall)){
       list = list_next;
 
       continue;
@@ -4779,7 +4865,9 @@ ags_channel_play(AgsChannel *channel,
 
     recall_flags = recall->flags;
         
-    if((AGS_RECALL_TEMPLATE & (recall_flags)) == 0){
+    if((AGS_RECALL_TEMPLATE & (recall_flags)) == 0 &&
+       (AGS_RECALL_RUN_FIRST & (recall_flags)) == 0 &&
+       (AGS_RECALL_RUN_LAST & (recall_flags)) == 0){
 #ifdef AGS_DEBUG
       g_message("%s play channel %x:%d @%x -> %x", G_OBJECT_TYPE_NAME(recall), channel, channel->line, recall, recall->recall_id);
 #endif
@@ -4802,6 +4890,64 @@ ags_channel_play(AgsChannel *channel,
     list = list_next;
   }
 
+  /* run - last */
+  list = list_start;
+
+  while(list != NULL){
+    guint recall_flags;
+    
+    list_next = list->next;
+
+    recall = AGS_RECALL(list->data);
+    
+    if(recall == NULL ||
+       !AGS_IS_RECALL(recall)){
+      list = list_next;
+      
+      continue;
+    }
+
+    if(AGS_IS_RECALL_CHANNEL(recall)){
+      list = list_next;
+
+      continue;
+    }
+
+    if(recall->recall_id == NULL ||
+       recall->recall_id->recycling_context != recall_id->recycling_context){
+      list = list_next;
+
+      continue;
+    }
+
+    recall_flags = recall->flags;
+        
+    if((AGS_RECALL_TEMPLATE & (recall_flags)) == 0 &&
+       (AGS_RECALL_RUN_LAST & (recall_flags)) != 0){
+#ifdef AGS_DEBUG
+      g_message("%s play channel %x:%d @%x -> %x", G_OBJECT_TYPE_NAME(recall), channel, channel->line, recall, recall->recall_id);
+#endif
+
+      if((AGS_RECALL_HIDE & (recall_flags)) == 0){
+	g_object_ref(recall);
+	
+	if(stage == 0){
+	  AGS_RECALL_GET_CLASS(recall)->run_pre(recall);
+	}else if(stage == 1){
+	  AGS_RECALL_GET_CLASS(recall)->run_inter(recall);
+	}else{
+	  AGS_RECALL_GET_CLASS(recall)->run_post(recall);
+	}
+
+	g_object_unref(recall);
+      }
+    }
+
+    g_object_unref(recall);
+
+    list = list_next;
+  }
+  
   g_list_free(list_start);
 }
 
@@ -8081,28 +8227,28 @@ ags_channel_recursive_play_init(AgsChannel *channel, gint stage,
 				 recall_id,
 				 -1, -1,
 				 TRUE, TRUE);
-    }else if(stage >= 0 && stage < 3){
+    }else if(stage >= 0 && stage < 4){
       ags_channel_recursive_init(channel,
 				 recall_id,
-				 ((stage == 0) ? -1: 3), stage,
+				 ((stage == 0) ? -1: 4), stage,
 				 TRUE, TRUE);
     }
   }else{
     if(duplicate_templates){
       ags_channel_recursive_init(channel,
 				 recall_id,
-				 0, 3,
+				 0, 4,
 				 TRUE, TRUE);
     }
 
     if(resolve_dependencies){
       ags_channel_recursive_init(channel,
 				 recall_id,
-				 1, 3,
+				 1, 4,
 				 TRUE, TRUE);
     }
 
-    if(stage == -1 || (stage >= 0 && stage < 3)){
+    if(stage == -1 || (stage >= 0 && stage < 4)){
       ags_channel_recursive_init(channel,
 				 recall_id,
 				 2, stage,
@@ -10604,7 +10750,7 @@ ags_channel_recursive_init(AgsChannel *channel,
 	}
       }else if(stage == 2){
 	if(init_stage == -1){
-	  for(init_stage = 0; init_stage < 3; init_stage++){
+	  for(init_stage = 0; init_stage < 4; init_stage++){
 	    /* init */
 	    if(init_down){
 	      ags_channel_recursive_init_down(channel,
@@ -10616,7 +10762,7 @@ ags_channel_recursive_init(AgsChannel *channel,
 					    recall_id);
 	    }
 	  }
-	}else if(init_stage >= 0 && init_stage < 3){
+	}else if(init_stage >= 0 && init_stage < 4){
 	  /* init */
 	  if(init_down){
 	    ags_channel_recursive_init_down(channel,
@@ -10644,7 +10790,7 @@ ags_channel_recursive_init(AgsChannel *channel,
       }
     }else if(stage == 2){
       if(init_stage == -1){
-	for(init_stage = 0; init_stage < 3; init_stage++){
+	for(init_stage = 0; init_stage < 4; init_stage++){
 	  /* init */
 	  if(init_down){
 	    ags_channel_recursive_init_down(channel,
@@ -10656,7 +10802,7 @@ ags_channel_recursive_init(AgsChannel *channel,
 					  recall_id);
 	  }
 	}
-      }else if(init_stage >= 0 && init_stage < 3){
+      }else if(init_stage >= 0 && init_stage < 4){
 	/* init */
 	if(init_down){
 	  ags_channel_recursive_init_down(channel,
@@ -10708,6 +10854,10 @@ ags_channel_recursive_run(AgsChannel *channel,
     pthread_mutex_t *audio_mutex;
     pthread_mutex_t *channel_mutex;
 
+    if(recall_id == NULL){
+      return;
+    }
+    
     /* get channel mutex */
     pthread_mutex_lock(application_mutex);
 
@@ -11011,6 +11161,10 @@ ags_channel_recursive_run(AgsChannel *channel,
     pthread_mutex_t *channel_mutex;
     pthread_mutex_t *current_mutex;
 
+    if(recall_id == NULL){
+      return;
+    }
+
     /* get channel mutex */
     pthread_mutex_lock(application_mutex);
 
@@ -11258,6 +11412,10 @@ ags_channel_recursive_cancel(AgsChannel *channel,
     pthread_mutex_t *audio_mutex;
     pthread_mutex_t *channel_mutex;
 
+    if(recall_id == NULL){
+      return;
+    }
+    
     /* get channel mutex */
     pthread_mutex_lock(application_mutex);
 
@@ -11551,6 +11709,10 @@ ags_channel_recursive_cancel(AgsChannel *channel,
     pthread_mutex_t *channel_mutex;
     pthread_mutex_t *current_mutex;
 
+    if(recall_id == NULL){
+      return;
+    }
+
     /* get channel mutex */
     pthread_mutex_lock(application_mutex);
 
diff --git a/ags/audio/ags_devin.c b/ags/audio/ags_devin.c
index fabed49..0a55862 100644
--- a/ags/audio/ags_devin.c
+++ b/ags/audio/ags_devin.c
@@ -19,13 +19,7 @@
 
 #include <ags/audio/ags_devin.h>
 
-#include <ags/lib/ags_time.h>
-
-#include <ags/object/ags_application_context.h>
-#include <ags/object/ags_config.h>
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_soundcard.h>
-#include <ags/object/ags_concurrent_tree.h>
+#include <ags/libags.h>
 
 #include <ags/audio/ags_sound_provider.h>
 #include <ags/audio/ags_audio_buffer_util.h>
diff --git a/ags/audio/ags_devout.c b/ags/audio/ags_devout.c
index 9e41009..fcadba7 100644
--- a/ags/audio/ags_devout.c
+++ b/ags/audio/ags_devout.c
@@ -19,13 +19,7 @@
 
 #include <ags/audio/ags_devout.h>
 
-#include <ags/lib/ags_time.h>
-
-#include <ags/object/ags_application_context.h>
-#include <ags/object/ags_config.h>
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_soundcard.h>
-#include <ags/object/ags_concurrent_tree.h>
+#include <ags/libags.h>
 
 #include <ags/audio/ags_sound_provider.h>
 #include <ags/audio/ags_audio_buffer_util.h>
@@ -1745,6 +1739,7 @@ ags_devout_pcm_info(AgsSoundcard *soundcard,
 	device_fixup = g_strndup(card_id,
 				 index(card_id,
 				       ',') - card_id);
+	handle = NULL;
 	
 	rc = snd_pcm_open(&handle, device_fixup, SND_PCM_STREAM_PLAYBACK, 0);
       
@@ -1761,6 +1756,16 @@ ags_devout_pcm_info(AgsSoundcard *soundcard,
 	  
 	  return;
 	}
+      }else{
+	if(error != NULL){
+	  g_set_error(error,
+		      AGS_DEVOUT_ERROR,
+		      AGS_DEVOUT_ERROR_LOCKED_SOUNDCARD,
+		      "unable to open pcm device: %s\n",
+		      str);
+	}
+	
+	return;
       }
     }
 
@@ -1952,6 +1957,8 @@ ags_devout_is_available(AgsSoundcard *soundcard)
     signed short revents;
 
     if((AGS_DEVOUT_ALSA & (devout->flags)) != 0){
+      revents = 0;
+      
 #ifdef AGS_WITH_ALSA
       snd_pcm_poll_descriptors_revents(devout->out.alsa.handle, AGS_POLL_FD(list->data)->poll_fd, 1, &revents);
 #endif
@@ -2869,7 +2876,9 @@ ags_devout_alsa_init(AgsSoundcard *soundcard,
   /*  */
   period_event = 0;
   
-  /* Open PCM device for playback. */
+  /* Open PCM device for playback. */  
+  handle = NULL;
+
   if((err = snd_pcm_open(&handle, devout->out.alsa.device, SND_PCM_STREAM_PLAYBACK, 0)) < 0){
     gchar *device_fixup;
     
@@ -2878,6 +2887,8 @@ ags_devout_alsa_init(AgsSoundcard *soundcard,
     
     device_fixup = g_strdup_printf("%s,0",
 				   devout->out.alsa.device);
+
+    handle = NULL;
     
     if((err = snd_pcm_open(&handle, device_fixup, SND_PCM_STREAM_PLAYBACK, 0)) < 0){
       pthread_mutex_unlock(mutex);
@@ -3088,6 +3099,7 @@ ags_devout_alsa_init(AgsSoundcard *soundcard,
   
   /* write the parameters to device */
   err = snd_pcm_hw_params(handle, hwparams);
+
   if (err < 0) {
     pthread_mutex_unlock(mutex);
 
@@ -3935,7 +3947,7 @@ ags_devout_adjust_delay_and_attack(AgsDevout *devout)
   gint next_attack;
   guint i;
 
-  if(devout == NULL){
+  if(!AGS_IS_DEVOUT(devout)){
     return;
   }
   
diff --git a/ags/audio/ags_notation.c b/ags/audio/ags_notation.c
index 68e3c9f..b8bb253 100644
--- a/ags/audio/ags_notation.c
+++ b/ags/audio/ags_notation.c
@@ -1133,8 +1133,9 @@ ags_notation_is_note_selected(AgsNotation *notation, AgsNote *note)
   selection = notation->selection;
 
   while(selection != NULL && AGS_NOTE(selection->data)->x[0] <= note->x[0]){
-    if(selection->data == note)
+    if(selection->data == note){
       return(TRUE);
+    }
 
     selection = selection->next;
   }
@@ -1406,6 +1407,7 @@ ags_notation_add_region_to_selection(AgsNotation *notation,
 				     gboolean replace_current_selection)
 {
   AgsNote *note;
+
   GList *region, *list;
 
   region = ags_notation_find_region(notation,
@@ -1445,7 +1447,6 @@ ags_notation_add_region_to_selection(AgsNotation *notation,
   }
 }
 
-
 /**
  * ags_notation_remove_region_from_selection:
  * @notation: an #AgsNotation
@@ -1464,6 +1465,7 @@ ags_notation_remove_region_from_selection(AgsNotation *notation,
 					  guint x1, guint y1)
 {
   AgsNote *note;
+  
   GList *region;
 
   region = ags_notation_find_region(notation,
@@ -1498,8 +1500,10 @@ xmlNode*
 ags_notation_copy_selection(AgsNotation *notation)
 {
   AgsNote *note;
+
   xmlNode *notation_node, *current_note;
   xmlNode *timestamp_node;
+
   GList *selection;
 
   guint x_boundary, y_boundary;
@@ -1634,8 +1638,8 @@ ags_notation_cut_selection(AgsNotation *notation)
  * @x_offset: region start cursor offset
  * @reset_y_offset: if %TRUE @y_offset used as cursor
  * @y_offset: region start cursor tone
- * @match_channel: 
- * @no_duplicates: 
+ * @match_channel: only paste if channel matches
+ * @no_duplicates: only paste if current note doesn't exist
  *
  * Paste previously copied notes. 
  *
@@ -1650,6 +1654,8 @@ ags_notation_insert_native_piano_from_clipboard(AgsNotation *notation,
 						gboolean reset_y_offset, guint y_offset,
 						gboolean match_channel, gboolean no_duplicates)
 {
+  gboolean match_timestamp;
+  
   auto void ags_notation_insert_native_piano_from_clipboard_version_0_3_12();
   
   void ags_notation_insert_native_piano_from_clipboard_version_0_3_12()
@@ -1865,7 +1871,8 @@ ags_notation_insert_native_piano_from_clipboard(AgsNotation *notation,
 	  }
 
 	  /* check duplicate */
-	  if(ags_notation_find_point(notation,
+	  if(no_duplicates &&
+	     ags_notation_find_point(notation,
 				     x0_val, y_val,
 				     FALSE) != NULL){
 	    node = node->next;
@@ -1874,37 +1881,24 @@ ags_notation_insert_native_piano_from_clipboard(AgsNotation *notation,
 	  }
 	  
 	  /* add note */
-	  note = ags_note_new();
+	  if(!match_timestamp ||
+	     x0_val < notation->timestamp->timer.ags_offset.offset + AGS_NOTATION_DEFAULT_OFFSET){
+	    note = ags_note_new();
 
-	  note->x[0] = x0_val;
-	  note->x[1] = x1_val;
+	    note->x[0] = x0_val;
+	    note->x[1] = x1_val;
 
-	  note->y = y_val;
+	    note->y = y_val;
 
 #ifdef AGS_DEBUG
-	  g_message("adding note at: [%u,%u|%u]\n", x0_val, x1_val, y_val);
+	    g_message("adding note at: [%u,%u|%u]\n", x0_val, x1_val, y_val);
 #endif
-	  
-	  ags_notation_add_note(notation,
-				note,
-				FALSE);
-	}
-      }else if(!xmlStrncmp("timestamp",
-			   node->name,
-			   10)){
-	/* retrieve timer offset */
-	offset = xmlGetProp(node, "offset");
-
-	if(notation->timestamp == NULL){
-	  notation->timestamp = ags_timestamp_new();
-
-	  AGS_TIMESTAMP(notation->timestamp)->flags &= (~AGS_TIMESTAMP_UNIX);
-	  AGS_TIMESTAMP(notation->timestamp)->flags |= AGS_TIMESTAMP_OFFSET;
+	    
+	    ags_notation_add_note(notation,
+				  note,
+				  FALSE);
+	  }
 	}
-
-	AGS_TIMESTAMP(notation->timestamp)->timer.ags_offset.offset = g_ascii_strtoull(offset,
-										       NULL,
-										       10);
       }
     
       node = node->next;
@@ -1914,6 +1908,8 @@ ags_notation_insert_native_piano_from_clipboard(AgsNotation *notation,
   if(!AGS_IS_NOTATION(notation)){
     return;
   }
+
+  match_timestamp = TRUE;
   
   if(!xmlStrncmp("0.3.12", version, 7)){
     ags_notation_insert_native_piano_from_clipboard_version_0_3_12();
@@ -1922,6 +1918,8 @@ ags_notation_insert_native_piano_from_clipboard(AgsNotation *notation,
     ags_notation_insert_native_piano_from_clipboard_version_0_3_12();
   }else if(!xmlStrncmp("1.2.0", version, 7)){
     /* changes contain only optional informations */
+    match_timestamp = TRUE;
+    
     if(match_channel &&
        notation->audio_channel != g_ascii_strtoull(xmlGetProp(root_node,
 							      "audio-channel"),
@@ -1960,6 +1958,21 @@ ags_notation_insert_from_clipboard(AgsNotation *notation,
 					      FALSE, FALSE);
 }
 
+/**
+ * ags_notation_insert_from_clipboard_extended:
+ * @notation: an #AgsNotation
+ * @notation_node: the clipboard XML data
+ * @reset_x_offset: if %TRUE @x_offset used as cursor
+ * @x_offset: region start cursor offset
+ * @reset_y_offset: if %TRUE @y_offset used as cursor
+ * @y_offset: region start cursor tone
+ * @match_channel: only paste if channel matches
+ * @no_duplicates: only paste if current note doesn't exist
+ * 
+ * Paste previously copied notes. 
+ * 
+ * Since: 1.3.0
+ */
 void
 ags_notation_insert_from_clipboard_extended(AgsNotation *notation,
 					    xmlNode *notation_node,
diff --git a/ags/audio/ags_note.c b/ags/audio/ags_note.c
index a2c57d5..fa51b9c 100644
--- a/ags/audio/ags_note.c
+++ b/ags/audio/ags_note.c
@@ -326,9 +326,12 @@ ags_note_init(AgsNote *note)
   note->flags = 0;
 
   note->x[0] = 0;
-  note->x[1] = 0;
+  note->x[1] = 1;
   note->y = 0;
 
+  note->rt_offset = 0;
+  note->rt_attack = 0;
+  
   note->stream_delay = 0.0;
   note->stream_attack = 0;
 
@@ -1215,7 +1218,12 @@ ags_note_new()
 }
 
 /**
- * ags_note_new:
+ * ags_note_new_with_offset:
+ * @x0: x0
+ * @x1: x1
+ * @y: y
+ * @stream_delay: delay
+ * @stream_attack: attack
  *
  * Creates an #AgsNote
  *
diff --git a/ags/audio/ags_note.h b/ags/audio/ags_note.h
index a5c68e4..08ea860 100644
--- a/ags/audio/ags_note.h
+++ b/ags/audio/ags_note.h
@@ -75,6 +75,9 @@ struct _AgsNote
   guint x[2];
   guint y;
 
+  guint64 rt_offset;
+  guint rt_attack;
+  
   gdouble stream_delay;
   gdouble stream_attack;
   
diff --git a/ags/audio/ags_playback.c b/ags/audio/ags_playback.c
index b8a0d4f..a85b002 100644
--- a/ags/audio/ags_playback.c
+++ b/ags/audio/ags_playback.c
@@ -22,6 +22,7 @@
 #include <ags/libags.h>
 
 #include <ags/audio/ags_channel.h>
+#include <ags/audio/ags_note.h>
 
 #include <ags/audio/thread/ags_channel_thread.h>
 #include <ags/audio/thread/ags_iterator_thread.h>
@@ -126,7 +127,7 @@ ags_playback_class_init(AgsPlaybackClass *playback)
    *
    * The parent playback domain.
    * 
-   * Since: 1.0.0.7
+   * Since: 1.0.0
    */
   param_spec = g_param_spec_object("playback-domain",
 				   i18n_pspec("parent playback domain"),
@@ -142,7 +143,7 @@ ags_playback_class_init(AgsPlaybackClass *playback)
    *
    * The assigned source.
    * 
-   * Since: 1.0.0.7
+   * Since: 1.0.0
    */
   param_spec = g_param_spec_object("source",
 				   i18n_pspec("assigned source"),
@@ -158,7 +159,7 @@ ags_playback_class_init(AgsPlaybackClass *playback)
    *
    * The assigned audio channel.
    * 
-   * Since: 1.0.0.7
+   * Since: 1.0.0
    */
   param_spec = g_param_spec_uint("audio-channel",
 				 i18n_pspec("assigned audio channel"),
@@ -249,6 +250,9 @@ ags_playback_init(AgsPlayback *playback)
   playback->source = NULL;
   playback->audio_channel = 0;
 
+  playback->play_note = ags_note_new();
+  g_object_ref(playback->play_note);
+  
   /* samplerate and buffer size */
   samplerate = AGS_SOUNDCARD_DEFAULT_SAMPLERATE;
   buffer_size = AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE;
@@ -415,6 +419,8 @@ ags_playback_set_property(GObject *gobject,
       if(source != NULL){
 	g_object_ref(G_OBJECT(source));
 
+	AGS_NOTE(playback->play_note)->y = AGS_CHANNEL(source)->pad;
+      
 	if(AGS_IS_CHANNEL(source) &&
 	   ((AGS_PLAYBACK_SUPER_THREADED_CHANNEL & (g_atomic_int_get(&(playback->flags)))) != 0 ||
 	    (AGS_PLAYBACK_SUPER_THREADED_RECYCLING & (g_atomic_int_get(&(playback->flags)))) != 0)){
@@ -698,7 +704,7 @@ ags_playback_disconnect(AgsConnectable *connectable)
  * 
  * Set channel thread of appropriate scope.
  * 
- * Since: 1.0.0.7
+ * Since: 1.0.0
  */
 void
 ags_playback_set_channel_thread(AgsPlayback *playback,
@@ -730,7 +736,7 @@ ags_playback_set_channel_thread(AgsPlayback *playback,
  * 
  * Returns: the matching #AgsThread or %NULL
  * 
- * Since: 1.0.0.7
+ * Since: 1.0.0
  */
 AgsThread*
 ags_playback_get_channel_thread(AgsPlayback *playback,
@@ -753,7 +759,7 @@ ags_playback_get_channel_thread(AgsPlayback *playback,
  * 
  * Set iterator thread of appropriate scope.
  * 
- * Since: 1.0.0.7
+ * Since: 1.0.0
  */
 void
 ags_playback_set_iterator_thread(AgsPlayback *playback,
@@ -785,7 +791,7 @@ ags_playback_set_iterator_thread(AgsPlayback *playback,
  * 
  * Returns: the matching #AgsThread or %NULL
  * 
- * Since: 1.0.0.7
+ * Since: 1.0.0
  */
 AgsThread*
 ags_playback_get_iterator_thread(AgsPlayback *playback,
@@ -808,7 +814,7 @@ ags_playback_get_iterator_thread(AgsPlayback *playback,
  * 
  * Set recycling thread of appropriate scope.
  * 
- * Since: 1.0.0.7
+ * Since: 1.0.0
  */
 void
 ags_playback_set_recycling_thread(AgsPlayback *playback,
@@ -840,7 +846,7 @@ ags_playback_set_recycling_thread(AgsPlayback *playback,
  * 
  * Returns: the matching #AgsThread or %NULL
  * 
- * Since: 1.0.0.7
+ * Since: 1.0.0
  */
 AgsThread*
 ags_playback_get_recycling_thread(AgsPlayback *playback,
@@ -863,7 +869,7 @@ ags_playback_get_recycling_thread(AgsPlayback *playback,
  * 
  * Set recall id of appropriate scope.
  * 
- * Since: 1.0.0.7
+ * Since: 1.0.0
  */
 void
 ags_playback_set_recall_id(AgsPlayback *playback,
@@ -895,7 +901,7 @@ ags_playback_set_recall_id(AgsPlayback *playback,
  * 
  * Returns: the matching #AgsRecallID or %NULL
  * 
- * Since: 1.0.0.7
+ * Since: 1.0.0
  */
 AgsRecallID*
 ags_playback_get_recall_id(AgsPlayback *playback,
diff --git a/ags/audio/ags_playback.h b/ags/audio/ags_playback.h
index 0ad8b9b..816d66d 100644
--- a/ags/audio/ags_playback.h
+++ b/ags/audio/ags_playback.h
@@ -87,6 +87,8 @@ struct _AgsPlayback
   GObject *source;
   guint audio_channel;
 
+  GObject *play_note;
+  
   AgsThread **channel_thread;
   AgsThread **iterator_thread;
 
diff --git a/ags/audio/ags_recall.c b/ags/audio/ags_recall.c
index 1670b1a..31fbf29 100644
--- a/ags/audio/ags_recall.c
+++ b/ags/audio/ags_recall.c
@@ -126,6 +126,7 @@ enum{
   RUN_INIT_PRE,
   RUN_INIT_INTER,
   RUN_INIT_POST,
+  CHECK_RT_STREAM,
   AUTOMATE,
   RUN_PRE,
   RUN_INTER,
@@ -360,6 +361,7 @@ ags_recall_class_init(AgsRecallClass *recall)
   recall->run_init_pre = ags_recall_real_run_init_pre;
   recall->run_init_inter = ags_recall_real_run_init_inter;
   recall->run_init_post = ags_recall_real_run_init_post;
+  recall->check_rt_stream = NULL;
 
   recall->automate = NULL;
   recall->run_pre = ags_recall_real_run_pre;
@@ -487,6 +489,24 @@ ags_recall_class_init(AgsRecallClass *recall)
 		 G_TYPE_NONE, 0);
 
   /**
+   * AgsRecall::check-rt-stream:
+   * @recall: the #AgsRecall to initialize
+   *
+   * The ::check-rt-stream signal notifies about initializing
+   * stage 0.
+   *
+   * Since: 1.4.0
+   */
+  recall_signals[CHECK_RT_STREAM] =
+    g_signal_new("check-rt-stream",
+		 G_TYPE_FROM_CLASS(recall),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsRecallClass, check_rt_stream),
+		 NULL, NULL,
+		 g_cclosure_marshal_VOID__VOID,
+		 G_TYPE_NONE, 0);
+
+  /**
    * AgsRecall::automate:
    * @recall: the #AgsRecall to play 
    *
@@ -737,10 +757,34 @@ ags_recall_plugin_interface_init(AgsPluginInterface *plugin)
 void
 ags_recall_init(AgsRecall *recall)
 {
+  AgsConfig *config;
+
+  gchar *str;
+
+  gboolean rt_safe;
+  
   pthread_mutexattr_t *attr;
 
+  config = ags_config_get_instance();
+
+  rt_safe = TRUE;
+  
+  str = ags_config_get_value(config,
+			     AGS_CONFIG_GENERIC,
+			     "rt-safe");
+
+  /* rt-safe */
+  if(str != NULL &&
+     !g_ascii_strncasecmp(str,
+			  "false",
+			  6)){
+    rt_safe = FALSE;
+  }
+  
   recall->flags = 0;
 
+  recall->rt_safe = rt_safe;
+  
   /* soundcard */
   recall->soundcard = NULL;
 
@@ -1736,6 +1780,25 @@ ags_recall_run_init_post(AgsRecall *recall)
 }
 
 /**
+ * ags_recall_check_rt_stream:
+ * @recall: an #AgsRecall
+ *
+ * Prepare for run, this is the pre stage within the preparation.
+ * 
+ * Since: 1.4.0
+ */
+void
+ags_recall_check_rt_stream(AgsRecall *recall)
+{
+  g_return_if_fail(AGS_IS_RECALL(recall));
+
+  g_object_ref(G_OBJECT(recall));
+  g_signal_emit(G_OBJECT(recall),
+		recall_signals[CHECK_RT_STREAM], 0);
+  g_object_unref(G_OBJECT(recall));
+}
+
+/**
  * ags_recall_automate:
  * @recall: an #AgsRecall
  *
@@ -2074,13 +2137,14 @@ ags_recall_real_remove(AgsRecall *recall)
   g_object_ref(recall);
 
   if(recall->parent == NULL){
+#if 0
     if(destroy_worker != NULL){
       ags_destroy_worker_add(destroy_worker,
-			     recall, ags_destroy_util_dispose_and_unref);
+			     recall, g_object_run_dispose);
     }else{
       g_object_run_dispose(recall);
-      g_object_unref(recall);
     }
+#endif
     
     return;
   }else{
diff --git a/ags/audio/ags_recall.h b/ags/audio/ags_recall.h
index c55a119..e2f0695 100644
--- a/ags/audio/ags_recall.h
+++ b/ags/audio/ags_recall.h
@@ -131,7 +131,8 @@ struct _AgsRecall
   GObject object;
 
   guint flags;
-
+  gboolean rt_safe;
+  
   gchar *version;
   gchar *build_id;
 
@@ -176,12 +177,13 @@ struct _AgsRecallClass
   void (*run_init_pre)(AgsRecall *recall);
   void (*run_init_inter)(AgsRecall *recall);
   void (*run_init_post)(AgsRecall *recall);
-
+  void (*check_rt_stream)(AgsRecall *recall);
+  
   void (*automate)(AgsRecall *recall);
   void (*run_pre)(AgsRecall *recall);
   void (*run_inter)(AgsRecall *recall);
   void (*run_post)(AgsRecall *recall);
-
+  
   void (*stop_persistent)(AgsRecall *recall);
   void (*done)(AgsRecall *recall);
 
@@ -228,6 +230,7 @@ void ags_recall_child_added(AgsRecall *parent, AgsRecall *child);
 void ags_recall_run_init_pre(AgsRecall *recall);
 void ags_recall_run_init_inter(AgsRecall *recall);
 void ags_recall_run_init_post(AgsRecall *recall);
+void ags_recall_check_rt_stream(AgsRecall *recall);
 
 void ags_recall_automate(AgsRecall *recall);
 void ags_recall_run_pre(AgsRecall *recall);
diff --git a/ags/audio/ags_recall_dssi.c b/ags/audio/ags_recall_dssi.c
index a21d813..f4ef67e 100644
--- a/ags/audio/ags_recall_dssi.c
+++ b/ags/audio/ags_recall_dssi.c
@@ -418,7 +418,7 @@ ags_recall_dssi_set_ports(AgsPlugin *plugin, GList *port)
 	    recall_dssi->input_port[0] = i;
 	  }else{
 	    recall_dssi->input_port = (unsigned long *) realloc(recall_dssi->input_port,
-								  (recall_dssi->input_lines + 1) * sizeof(unsigned long));
+								(recall_dssi->input_lines + 1) * sizeof(unsigned long));
 	    recall_dssi->input_port[recall_dssi->input_lines] = i;
 	  }
 
@@ -429,7 +429,7 @@ ags_recall_dssi_set_ports(AgsPlugin *plugin, GList *port)
 	    recall_dssi->output_port[0] = i;
 	  }else{
 	    recall_dssi->output_port = (unsigned long *) realloc(recall_dssi->output_port,
-								   (recall_dssi->output_lines + 1) * sizeof(unsigned long));
+								 (recall_dssi->output_lines + 1) * sizeof(unsigned long));
 	    recall_dssi->output_port[recall_dssi->output_lines] = i;
 	  }
 
diff --git a/ags/audio/ags_recall_dssi_run.c b/ags/audio/ags_recall_dssi_run.c
index a945964..b4fe11e 100644
--- a/ags/audio/ags_recall_dssi_run.c
+++ b/ags/audio/ags_recall_dssi_run.c
@@ -20,11 +20,11 @@
 #include <ags/audio/ags_recall_dssi.h>
 #include <ags/audio/ags_recall_dssi_run.h>
 
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_plugin.h>
+#include <ags/libags.h>
 
 #include <ags/plugin/ags_dssi_manager.h>
 
+#include <ags/audio/ags_input.h>
 #include <ags/audio/ags_port.h>
 #include <ags/audio/ags_note.h>
 #include <ags/audio/ags_audio_buffer_util.h>
@@ -157,10 +157,21 @@ ags_recall_dssi_run_init(AgsRecallDssiRun *recall_dssi_run)
   recall_dssi_run->input = NULL;
   recall_dssi_run->output = NULL;
 
+  recall_dssi_run->port_data = NULL;
+  
   recall_dssi_run->delta_time = 0;
   
-  recall_dssi_run->event_buffer = NULL;
-  recall_dssi_run->event_count = NULL;
+  recall_dssi_run->event_buffer = (snd_seq_event_t **) malloc(2 * sizeof(snd_seq_event_t *));
+
+  recall_dssi_run->event_buffer[0] = (snd_seq_event_t *) malloc(sizeof(snd_seq_event_t));
+  memset(recall_dssi_run->event_buffer[0], 0, sizeof(snd_seq_event_t));
+  
+  recall_dssi_run->event_buffer[1] = NULL;
+
+  recall_dssi_run->event_count = (unsigned long *) malloc(2 * sizeof(unsigned long));
+
+  recall_dssi_run->event_count[0] = 0;
+  recall_dssi_run->event_count[1] = 0;
 
   recall_dssi_run->note = NULL;
   recall_dssi_run->route_dssi_audio_run = NULL;
@@ -183,6 +194,7 @@ ags_recall_dssi_run_finalize(GObject *gobject)
 {
   AgsRecallDssi *recall_dssi;
   AgsRecallDssiRun *recall_dssi_run;
+  
   unsigned long i;
 
   recall_dssi_run = AGS_RECALL_DSSI_RUN(gobject);
@@ -190,16 +202,41 @@ ags_recall_dssi_run_finalize(GObject *gobject)
   free(recall_dssi_run->output);
   free(recall_dssi_run->input);
 
-  free(recall_dssi_run->event_buffer[0]);
-  free(recall_dssi_run->event_buffer);
-  free(recall_dssi_run->event_count);    
+  if(recall_dssi_run->port_data != NULL){
+    free(recall_dssi_run->port_data);
+  }
+  
+  if(recall_dssi_run->event_buffer != NULL){
+    if(recall_dssi_run->event_buffer[0] != NULL){
+      free(recall_dssi_run->event_buffer[0]);
+    }
+    
+    free(recall_dssi_run->event_buffer);
+  }
+
+  if(recall_dssi_run->event_count != NULL){
+    free(recall_dssi_run->event_count);
+  }
 
   free(recall_dssi_run->ladspa_handle);
 
   if(recall_dssi_run->route_dssi_audio_run != NULL){
-    AGS_ROUTE_DSSI_AUDIO_RUN(recall_dssi_run->route_dssi_audio_run)->feed_midi = g_list_remove(AGS_ROUTE_DSSI_AUDIO_RUN(recall_dssi_run->route_dssi_audio_run)->feed_midi,
-											       recall_dssi_run->note);
+    GList *note;
+
+    note = recall_dssi_run->note;
+
+    while(note != NULL){
+      //FIXME:JK: ref counting
+      AGS_ROUTE_DSSI_AUDIO_RUN(recall_dssi_run->route_dssi_audio_run)->feed_midi = g_list_remove(AGS_ROUTE_DSSI_AUDIO_RUN(recall_dssi_run->route_dssi_audio_run)->feed_midi,
+												 note->data);
+      g_object_unref(note->data);
+
+      note = note->next;
+    }
   }
+
+  g_list_free_full(recall_dssi_run->note,
+		   g_object_unref);
   
   /* call parent */
   G_OBJECT_CLASS(ags_recall_dssi_run_parent_class)->finalize(gobject);
@@ -211,6 +248,8 @@ ags_recall_dssi_run_run_init_pre(AgsRecall *recall)
   AgsRecallDssi *recall_dssi;
   AgsRecallDssiRun *recall_dssi_run;
   AgsAudioSignal *audio_signal;
+
+  unsigned long port_count;
   unsigned long samplerate;
   unsigned long buffer_size;
   unsigned long i, i_stop;
@@ -267,87 +306,27 @@ ags_recall_dssi_run_run_init_pre(AgsRecall *recall)
 
   ags_recall_dssi_run_load_ports(recall_dssi_run);
 
-  for(i = 0; i < i_stop; i++){
-    if(recall_dssi->plugin_descriptor->LADSPA_Plugin->activate != NULL){
-      recall_dssi->plugin_descriptor->LADSPA_Plugin->activate(recall_dssi_run->ladspa_handle[i]);
-    }
-    
-#ifdef AGS_DEBUG
-    g_message("instantiate DSSI handle");
-#endif
-
-  }
+  port_count = recall_dssi->plugin_descriptor->LADSPA_Plugin->PortCount;
 
-  /* select program */
-  if(recall_dssi->plugin_descriptor->select_program != NULL){
+  if(port_count > 0){
     AgsPort *current;
     
-    GList *list, *port;
-    
-    gchar *specifier;
+    GList *list;
 
-    LADSPA_Data *port_data;
-    
-    unsigned long port_count;
+    gchar *specifier;
     
-    port = AGS_RECALL(recall_dssi)->port;
-
-    port_count = recall_dssi->plugin_descriptor->LADSPA_Plugin->PortCount;
-    port_data = (LADSPA_Data *) malloc(port_count * sizeof(LADSPA_Data));
+    recall_dssi_run->port_data = (LADSPA_Data *) malloc(port_count * sizeof(LADSPA_Data));
+  }
   
-    for(i = 0; i < port_count; i++){
-      specifier = recall_dssi->plugin_descriptor->LADSPA_Plugin->PortNames[i];
-      list = port;
-
-      while(list != NULL){
-	current = list->data;
-
-	if(!g_strcmp0(specifier,
-		      current->specifier)){
-	  break;
-	}
-
-	list = list->next;
-      }
-
-      if(list == NULL){
-	port_data[i] = 0.0;
-
-	//	g_warning("didn't find port");
-      }else{
-	port_data[i] = current->port_value.ags_port_ladspa;
-      }
+  for(i = 0; i < i_stop; i++){
+    if(recall_dssi->plugin_descriptor->LADSPA_Plugin->activate != NULL){
+      recall_dssi->plugin_descriptor->LADSPA_Plugin->activate(recall_dssi_run->ladspa_handle[i]);
     }
     
-    for(i = 0; i < i_stop; i++){
-      recall_dssi->plugin_descriptor->select_program(recall_dssi_run->ladspa_handle[i],
-						     recall_dssi->bank,
-						     recall_dssi->program);
-
-      //      g_message("b p %u %u", recall_dssi->bank, recall_dssi->program);
-    }
-
-    /* reset port data */    
-    for(i = 0; i < port_count; i++){
-      specifier = recall_dssi->plugin_descriptor->LADSPA_Plugin->PortNames[i];
-      list = port;
-
-      while(list != NULL){
-	current = list->data;
-
-	if(!g_strcmp0(specifier,
-		      current->specifier)){
-	  current->port_value.ags_port_ladspa = port_data[i];
-	  //	  g_message("%s %f", current->specifier, port_data[i]);
-	
-	  break;
-	}
-
-	list = list->next;
-      }
-    }
+#ifdef AGS_DEBUG
+    g_message("instantiate DSSI handle");
+#endif
 
-    free(port_data);
   }
 }
 
@@ -357,12 +336,23 @@ ags_recall_dssi_run_run_pre(AgsRecall *recall)
   AgsRecallDssi *recall_dssi;
   AgsRecallDssiRun *recall_dssi_run;
   AgsAudioSignal *audio_signal;
+  AgsPort *current;
 
   AgsCountBeatsAudioRun *count_beats_audio_run;
   AgsRouteDssiAudioRun *route_dssi_audio_run;
+    
+  GList *list, *port;
+  
+  GList *note, *note_next;
 
   snd_seq_event_t **event_buffer;
   unsigned long *event_count;
+    
+  gchar *specifier;
+  
+  LADSPA_Data port_data;
+  
+  unsigned long port_count;
   
   guint copy_mode_in, copy_mode_out;
   unsigned long buffer_size;
@@ -370,11 +360,22 @@ ags_recall_dssi_run_run_pre(AgsRecall *recall)
   
   /* call parent */
   AGS_RECALL_CLASS(ags_recall_dssi_run_parent_class)->run_pre(recall);
+
+  if(recall->rt_safe &&
+     recall->recall_id->recycling_context->parent != NULL &&
+     AGS_RECALL_AUDIO_SIGNAL(recall)->source->note == NULL){
+    return;
+  }
   
   recall_dssi = AGS_RECALL_DSSI(AGS_RECALL_CHANNEL_RUN(recall->parent->parent)->recall_channel);
   recall_dssi_run = AGS_RECALL_DSSI_RUN(recall);
 
   route_dssi_audio_run = AGS_ROUTE_DSSI_AUDIO_RUN(recall_dssi_run->route_dssi_audio_run);
+
+  if(route_dssi_audio_run == NULL){
+    return;
+  }
+  
   count_beats_audio_run = route_dssi_audio_run->count_beats_audio_run;
 
   audio_signal = AGS_RECALL_AUDIO_SIGNAL(recall)->source;
@@ -386,26 +387,48 @@ ags_recall_dssi_run_run_pre(AgsRecall *recall)
     i_stop = recall_dssi->input_lines;
   }
 
-  if(audio_signal->stream_current == NULL ||
-     (AGS_NOTE(recall_dssi_run->note)->x[1] <= count_beats_audio_run->notation_counter &&
-      (AGS_NOTE_FEED & (AGS_NOTE(recall_dssi_run->note)->flags)) == 0) ||
-     AGS_NOTE(recall_dssi_run->note)->x[0] > count_beats_audio_run->notation_counter){
-    //    g_message("done");
+  if(AGS_RECALL(recall_dssi_run)->rt_safe){
+    note = recall_dssi_run->note;
+
+    while(note != NULL){
+      note_next = note->next;
+      
+      if((AGS_NOTE(note->data)->x[1] <= count_beats_audio_run->notation_counter &&
+	  (AGS_NOTE_FEED & (AGS_NOTE(note->data)->flags)) == 0) ||
+	 AGS_NOTE(note->data)->x[0] > count_beats_audio_run->notation_counter){
+	recall_dssi_run->note = g_list_remove(recall_dssi_run->note,
+					      note->data);
+      }
     
-    for(i = 0; i < i_stop; i++){
-      /* deactivate */
-      //TODO:JK: fix-me
-      if(recall_dssi->plugin_descriptor->LADSPA_Plugin->deactivate != NULL){
-	recall_dssi->plugin_descriptor->LADSPA_Plugin->deactivate(recall_dssi_run->ladspa_handle[i]);
+      note = note_next;
+    }
+
+    if(recall_dssi_run->note == NULL){
+      memset(recall_dssi_run->event_buffer[0], 0, sizeof(snd_seq_event_t));
+    }
+  }else{
+    if(audio_signal->stream_current == NULL ||
+       (AGS_NOTE(recall_dssi_run->note->data)->x[1] <= count_beats_audio_run->notation_counter &&
+	(AGS_NOTE_FEED & (AGS_NOTE(recall_dssi_run->note->data)->flags)) == 0) ||
+       AGS_NOTE(recall_dssi_run->note->data)->x[0] > count_beats_audio_run->notation_counter){
+      //    g_message("done");
+    
+      for(i = 0; i < i_stop; i++){
+	/* deactivate */
+	//TODO:JK: fix-me
+	if(recall_dssi->plugin_descriptor->LADSPA_Plugin->deactivate != NULL){
+	  recall_dssi->plugin_descriptor->LADSPA_Plugin->deactivate(recall_dssi_run->ladspa_handle[i]);
+	}
+      
+	recall_dssi->plugin_descriptor->LADSPA_Plugin->cleanup(recall_dssi_run->ladspa_handle[i]);
       }
+
+      ags_recall_done(recall);
       
-      recall_dssi->plugin_descriptor->LADSPA_Plugin->cleanup(recall_dssi_run->ladspa_handle[i]);
+      return;
     }
-
-    ags_recall_done(recall);
-    return;
   }
-
+  
   /* get copy mode and clear buffer */
   copy_mode_in = ags_audio_buffer_util_get_copy_mode(AGS_AUDIO_BUFFER_UTIL_FLOAT,
 						     ags_audio_buffer_util_format_from_soundcard(audio_signal->format));
@@ -429,28 +452,109 @@ ags_recall_dssi_run_run_pre(AgsRecall *recall)
 						audio_signal->stream_current->data, 1, 0,
 						(guint) buffer_size, copy_mode_in);
   }
+
+
+  /* select program */
+  port_count = recall_dssi->plugin_descriptor->LADSPA_Plugin->PortCount;
+
+  /* cache port data */    
+  for(i = 0; i < port_count; i++){
+    specifier = recall_dssi->plugin_descriptor->LADSPA_Plugin->PortNames[i];
+    list = AGS_RECALL(recall_dssi)->port;
+
+    while(list != NULL){
+      current = list->data;
+
+      if(!g_strcmp0(specifier,
+		    current->specifier)){
+	GValue value = {0,};
+	  
+	g_value_init(&value,
+		     G_TYPE_FLOAT);
+	ags_port_safe_read(current,
+			   &value);
+	
+	recall_dssi_run->port_data[i] = g_value_get_float(&value);
+	  
+	break;
+      }
+
+      list = list->next;
+    }
+  }
+  
+  if(recall_dssi->plugin_descriptor->select_program != NULL){    
+    for(i = 0; i < i_stop; i++){
+      recall_dssi->plugin_descriptor->select_program(recall_dssi_run->ladspa_handle[i],
+						     recall_dssi->bank,
+						     recall_dssi->program);
+
+      //      g_message("b p %u %u", recall_dssi->bank, recall_dssi->program);
+    }
+  }
+
+  /* reset port data */    
+  for(i = 0; i < port_count; i++){
+    current = NULL;
+    
+    specifier = recall_dssi->plugin_descriptor->LADSPA_Plugin->PortNames[i];
+
+    list = AGS_RECALL(recall_dssi)->port;
+
+    while(list != NULL){
+      current = list->data;
+
+      if(!g_strcmp0(specifier,
+		    current->specifier)){
+	break;
+      }
+
+      list = list->next;
+    }
+
+    if(list != NULL){
+      GValue value = {0,};
+      
+      g_value_init(&value,
+		   G_TYPE_FLOAT);
+      port_data = recall_dssi_run->port_data[i];
+
+      g_value_set_float(&value,
+			port_data);
+      ags_port_safe_write(current,
+			  &value);
+    }
+  }
   
   /* process data */
-  if(recall_dssi->plugin_descriptor->run_synth != NULL){
-    if(recall_dssi_run->event_buffer != NULL){
-      event_buffer = recall_dssi_run->event_buffer;
-      event_count = recall_dssi_run->event_count;
+  note = recall_dssi_run->note;
+
+  while(note != NULL){    
+    if(recall_dssi->plugin_descriptor->run_synth != NULL){
+      if(recall_dssi_run->event_buffer != NULL){
+	event_buffer = recall_dssi_run->event_buffer;
+	event_count = recall_dssi_run->event_count;
       
-      while(*event_buffer != NULL){
-	recall_dssi->plugin_descriptor->run_synth(recall_dssi_run->ladspa_handle[0],
-						  recall_dssi->output_lines * buffer_size,
-						  event_buffer[0],
-						  event_count[0]);
+	while(*event_buffer != NULL){
+	  if(event_buffer[0]->type == SND_SEQ_EVENT_NOTEON){
+	    recall_dssi->plugin_descriptor->run_synth(recall_dssi_run->ladspa_handle[0],
+						      recall_dssi->output_lines * buffer_size,
+						      event_buffer[0],
+						      event_count[0]);
+	  }
 	  
-	event_buffer++;
-	event_count++;
+	  event_buffer++;
+	  event_count++;
+	}
       }
+    }else if(recall_dssi->plugin_descriptor->LADSPA_Plugin->run != NULL){
+      recall_dssi->plugin_descriptor->LADSPA_Plugin->run(recall_dssi_run->ladspa_handle[0],
+							 buffer_size);
     }
-  }else if(recall_dssi->plugin_descriptor->LADSPA_Plugin->run != NULL){
-    recall_dssi->plugin_descriptor->LADSPA_Plugin->run(recall_dssi_run->ladspa_handle[0],
-						       buffer_size);
-  }
 
+    note = note->next;
+  }
+  
   /* copy data */
   if(recall_dssi_run->output != NULL){
     ags_audio_buffer_util_clear_buffer(audio_signal->stream_current->data, 1,
diff --git a/ags/audio/ags_recall_dssi_run.h b/ags/audio/ags_recall_dssi_run.h
index 8c09f9e..2182cdc 100644
--- a/ags/audio/ags_recall_dssi_run.h
+++ b/ags/audio/ags_recall_dssi_run.h
@@ -45,16 +45,18 @@ struct _AgsRecallDssiRun
   LADSPA_Handle *ladspa_handle;
 
   unsigned long audio_channels;
-  
+
   LADSPA_Data *input;
   LADSPA_Data *output;
 
+  LADSPA_Data *port_data;
+
   long delta_time;
   
   snd_seq_event_t **event_buffer;
   unsigned long *event_count;
 
-  GObject *note;
+  GList *note;
   GObject *route_dssi_audio_run;
 };
 
diff --git a/ags/audio/ags_recall_factory.c b/ags/audio/ags_recall_factory.c
index 879928e..ea611bf 100644
--- a/ags/audio/ags_recall_factory.c
+++ b/ags/audio/ags_recall_factory.c
@@ -55,6 +55,8 @@
 #include <ags/audio/recall/ags_feed_channel_run.h>
 #include <ags/audio/recall/ags_stream_channel.h>
 #include <ags/audio/recall/ags_stream_channel_run.h>
+#include <ags/audio/recall/ags_rt_stream_channel.h>
+#include <ags/audio/recall/ags_rt_stream_channel_run.h>
 #include <ags/audio/recall/ags_buffer_channel.h>
 #include <ags/audio/recall/ags_buffer_channel_run.h>
 #include <ags/audio/recall/ags_copy_pattern_audio.h>
@@ -126,6 +128,12 @@ GList* ags_recall_factory_create_stream(AgsAudio *audio,
 					guint start_audio_channel, guint stop_audio_channel,
 					guint start_pad, guint stop_pad,
 					guint create_flags, guint recall_flags);
+GList* ags_recall_factory_create_rt_stream(AgsAudio *audio,
+					   AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
+					   gchar *plugin_name,
+					   guint start_audio_channel, guint stop_audio_channel,
+					   guint start_pad, guint stop_pad,
+					   guint create_flags, guint recall_flags);
 GList* ags_recall_factory_create_buffer(AgsAudio *audio,
 					AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
 					gchar *plugin_name,
@@ -1965,6 +1973,227 @@ ags_recall_factory_create_stream(AgsAudio *audio,
 }
 
 GList*
+ags_recall_factory_create_rt_stream(AgsAudio *audio,
+				    AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
+				    gchar *plugin_name,
+				    guint start_audio_channel, guint stop_audio_channel,
+				    guint start_pad, guint stop_pad,
+				    guint create_flags, guint recall_flags)
+{
+  AgsRtStreamChannel *rt_stream_channel;
+  AgsRtStreamChannelRun *rt_stream_channel_run;
+  AgsChannel *output, *input;
+  AgsChannel *start, *channel;
+  AgsPort *port;
+
+  AgsMutexManager *mutex_manager;
+
+  GObject *soundcard;
+
+  GList *list;
+  GList *recall;
+
+  guint audio_channels;
+  guint i, j;
+
+  pthread_mutex_t *application_mutex;
+  pthread_mutex_t *audio_mutex;
+  pthread_mutex_t *channel_mutex;
+  
+  if(audio == NULL){
+    return(NULL);
+  }
+
+  mutex_manager = ags_mutex_manager_get_instance();
+  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
+
+  /* get audio mutex */
+  pthread_mutex_lock(application_mutex);
+
+  audio_mutex = ags_mutex_manager_lookup(mutex_manager,
+					 (GObject *) audio);
+  
+  pthread_mutex_unlock(application_mutex);
+
+  /* get some fields */
+  pthread_mutex_lock(audio_mutex);
+
+  soundcard = audio->soundcard;
+
+  output = audio->output;
+  input = audio->input;
+  
+  audio_channels = audio->audio_channels;
+  
+  pthread_mutex_unlock(audio_mutex);
+
+  /* get channel */
+  if((AGS_RECALL_FACTORY_OUTPUT & (create_flags)) != 0){
+    start =
+      channel = ags_channel_nth(output,
+				start_pad * audio_channels);
+  }else{
+    start =
+      channel = ags_channel_nth(input,
+				start_pad * audio_channels);
+  }
+
+  recall = NULL;
+
+  /* play */
+  if((AGS_RECALL_FACTORY_PLAY & (create_flags)) != 0){
+    if(play_container == NULL){
+      play_container = ags_recall_container_new();
+    }
+
+    play_container->flags |= AGS_RECALL_CONTAINER_PLAY;
+    ags_audio_add_recall_container(audio, (GObject *) play_container);
+
+    for(i = 0; i < stop_pad - start_pad; i++){
+      channel = ags_channel_nth(channel,
+				start_audio_channel);
+      
+      for(j = 0; j < stop_audio_channel - start_audio_channel; j++){
+	/* get channel mutex */
+	pthread_mutex_lock(application_mutex);
+	
+	channel_mutex = ags_mutex_manager_lookup(mutex_manager,
+						 (GObject *) channel);
+	
+	pthread_mutex_unlock(application_mutex);
+
+	/* add recall container */
+	ags_channel_add_recall_container(channel,
+					 (GObject *) play_container);
+
+	/* AgsRtStreamChannel */
+	rt_stream_channel = (AgsRtStreamChannel *) g_object_new(AGS_TYPE_RT_STREAM_CHANNEL,
+								"soundcard", soundcard,
+								"source", channel,
+								"recall_container", play_container,
+								NULL);
+							      
+	ags_recall_set_flags(AGS_RECALL(rt_stream_channel), (AGS_RECALL_TEMPLATE |
+							     (((AGS_RECALL_FACTORY_OUTPUT & create_flags) != 0) ? AGS_RECALL_OUTPUT_ORIENTATED: AGS_RECALL_INPUT_ORIENTATED) |
+							     AGS_RECALL_PLAYBACK |
+							     AGS_RECALL_SEQUENCER |
+							     AGS_RECALL_NOTATION));
+	ags_channel_add_recall(channel, (GObject *) rt_stream_channel, TRUE);
+	recall = g_list_prepend(recall,
+				rt_stream_channel);
+	ags_connectable_connect(AGS_CONNECTABLE(rt_stream_channel));
+
+	/* AgsRtStreamChannelRun */
+	rt_stream_channel_run = (AgsRtStreamChannelRun *) g_object_new(AGS_TYPE_RT_STREAM_CHANNEL_RUN,
+								       "soundcard", soundcard,
+								       "recall-channel", rt_stream_channel,
+								       "source", channel,
+								       "recall_container", play_container,
+								       NULL);
+	ags_recall_set_flags(AGS_RECALL(rt_stream_channel_run), (AGS_RECALL_TEMPLATE |
+								 (((AGS_RECALL_FACTORY_OUTPUT & create_flags) != 0) ? AGS_RECALL_OUTPUT_ORIENTATED: AGS_RECALL_INPUT_ORIENTATED) |
+								 AGS_RECALL_PLAYBACK |
+								 AGS_RECALL_SEQUENCER |
+								 AGS_RECALL_NOTATION));
+	ags_channel_add_recall(channel, (GObject *) rt_stream_channel_run, TRUE);
+	recall = g_list_prepend(recall,
+				rt_stream_channel_run);
+	ags_connectable_connect(AGS_CONNECTABLE(rt_stream_channel_run));
+
+	/* iterate */
+	pthread_mutex_lock(channel_mutex);
+	
+	channel = channel->next;
+
+	pthread_mutex_unlock(channel_mutex);
+      }
+
+      channel = ags_channel_nth(channel,
+				audio_channels - stop_audio_channel);
+    }
+  }
+
+  /* recall */
+  if((AGS_RECALL_FACTORY_RECALL & (create_flags)) != 0){
+    channel = start;
+
+    if(recall_container == NULL){
+      recall_container = ags_recall_container_new();
+    }
+
+    ags_audio_add_recall_container(audio, (GObject *) recall_container);
+
+    for(i = 0; i < stop_pad - start_pad; i++){
+      channel = ags_channel_nth(channel,
+				start_audio_channel);
+      
+      for(j = 0; j < stop_audio_channel - start_audio_channel; j++){
+	/* get channel mutex */
+	pthread_mutex_lock(application_mutex);
+	
+	channel_mutex = ags_mutex_manager_lookup(mutex_manager,
+						 (GObject *) channel);
+	
+	pthread_mutex_unlock(application_mutex);
+
+	/* add recall container */
+	ags_channel_add_recall_container(channel,
+					 (GObject *) recall_container);
+
+	/* AgsRtStreamChannel */
+	rt_stream_channel = (AgsRtStreamChannel *) g_object_new(AGS_TYPE_RT_STREAM_CHANNEL,
+								"soundcard", soundcard,
+								"source", channel,
+								"recall_container", recall_container,
+								NULL);
+							      
+	ags_recall_set_flags(AGS_RECALL(rt_stream_channel), (AGS_RECALL_TEMPLATE |
+							     (((AGS_RECALL_FACTORY_OUTPUT & create_flags) != 0) ? AGS_RECALL_OUTPUT_ORIENTATED: AGS_RECALL_INPUT_ORIENTATED) |
+							     AGS_RECALL_PLAYBACK |
+							     AGS_RECALL_SEQUENCER |
+							     AGS_RECALL_NOTATION));
+	ags_channel_add_recall(channel, (GObject *) rt_stream_channel, FALSE);
+	recall = g_list_prepend(recall,
+				rt_stream_channel);
+	ags_connectable_connect(AGS_CONNECTABLE(rt_stream_channel));
+
+	/* AgsRtStreamChannelRun */
+	rt_stream_channel_run = (AgsRtStreamChannelRun *) g_object_new(AGS_TYPE_RT_STREAM_CHANNEL_RUN,
+								       "soundcard", soundcard,
+								       "recall_channel", rt_stream_channel,
+								       "source", channel,
+								       "recall_container", recall_container,
+								       NULL);
+	ags_recall_set_flags(AGS_RECALL(rt_stream_channel_run), (AGS_RECALL_TEMPLATE |
+								 (((AGS_RECALL_FACTORY_OUTPUT & create_flags) != 0) ? AGS_RECALL_OUTPUT_ORIENTATED: AGS_RECALL_INPUT_ORIENTATED) |
+								 AGS_RECALL_PLAYBACK |
+								 AGS_RECALL_SEQUENCER |
+								 AGS_RECALL_NOTATION));
+	ags_channel_add_recall(channel, (GObject *) rt_stream_channel_run, FALSE);
+	recall = g_list_prepend(recall,
+				rt_stream_channel_run);
+	ags_connectable_connect(AGS_CONNECTABLE(rt_stream_channel_run));
+
+	/* iterate */
+	pthread_mutex_lock(channel_mutex);
+	
+	channel = channel->next;
+
+	pthread_mutex_unlock(channel_mutex);
+      }
+
+      channel = ags_channel_nth(channel,
+				audio_channels - stop_audio_channel);
+    }
+  }
+
+  /* return instantiated recall */
+  recall = g_list_reverse(recall);
+
+  return(recall);
+}
+
+GList*
 ags_recall_factory_create_buffer(AgsAudio *audio,
 				 AgsRecallContainer *play_container, AgsRecallContainer *recall_container,
 				 gchar *plugin_name,
@@ -5759,6 +5988,15 @@ ags_recall_factory_create(AgsAudio *audio,
 					      start_pad, stop_pad,
 					      create_flags, recall_flags);
   }else if(!strncmp(plugin_name,
+		    "ags-rt-stream",
+		    14)){
+    recall = ags_recall_factory_create_rt_stream(audio,
+						 play_container, recall_container,
+						 plugin_name,
+						 start_audio_channel, stop_audio_channel,
+						 start_pad, stop_pad,
+						 create_flags, recall_flags);
+  }else if(!strncmp(plugin_name,
 		    "ags-loop",
 		    9)){
     recall = ags_recall_factory_create_loop(audio,
diff --git a/ags/audio/ags_recall_ladspa_run.c b/ags/audio/ags_recall_ladspa_run.c
index 9bf73cd..85362cd 100644
--- a/ags/audio/ags_recall_ladspa_run.c
+++ b/ags/audio/ags_recall_ladspa_run.c
@@ -25,6 +25,7 @@
 
 #include <ags/plugin/ags_ladspa_manager.h>
 
+#include <ags/audio/ags_input.h>
 #include <ags/audio/ags_port.h>
 #include <ags/audio/ags_audio_buffer_util.h>
 
@@ -286,6 +287,12 @@ ags_recall_ladspa_run_run_inter(AgsRecall *recall)
   /* call parent */
   AGS_RECALL_CLASS(ags_recall_ladspa_run_parent_class)->run_inter(recall);
 
+  if(recall->rt_safe &&
+     recall->recall_id->recycling_context->parent != NULL &&
+     AGS_RECALL_AUDIO_SIGNAL(recall)->source->note == NULL){
+    return;
+  }
+
   recall_ladspa = AGS_RECALL_LADSPA(AGS_RECALL_CHANNEL_RUN(recall->parent->parent)->recall_channel);
   recall_ladspa_run = AGS_RECALL_LADSPA_RUN(recall);
 
diff --git a/ags/audio/ags_recall_lv2_run.c b/ags/audio/ags_recall_lv2_run.c
index fd9c81b..e781aad 100644
--- a/ags/audio/ags_recall_lv2_run.c
+++ b/ags/audio/ags_recall_lv2_run.c
@@ -20,17 +20,13 @@
 #include <ags/audio/ags_recall_lv2.h>
 #include <ags/audio/ags_recall_lv2_run.h>
 
-#include <ags/object/ags_application_context.h>
-#include <ags/object/ags_config.h>
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_plugin.h>
-
-#include <ags/thread/ags_mutex_manager.h>
+#include <ags/libags.h>
 
 #include <ags/plugin/ags_lv2_manager.h>
 #include <ags/plugin/ags_lv2_plugin.h>
 #include <ags/plugin/ags_lv2_worker.h>
 
+#include <ags/audio/ags_input.h>
 #include <ags/audio/ags_port.h>
 #include <ags/audio/ags_audio_buffer_util.h>
 
@@ -208,10 +204,23 @@ ags_recall_lv2_run_finalize(GObject *gobject)
   }
 
   if(recall_lv2_run->route_lv2_audio_run != NULL){
-    AGS_ROUTE_LV2_AUDIO_RUN(recall_lv2_run->route_lv2_audio_run)->feed_midi = g_list_remove(AGS_ROUTE_LV2_AUDIO_RUN(recall_lv2_run->route_lv2_audio_run)->feed_midi,
-											    recall_lv2_run->note);
+    GList *note;
+
+    note = recall_lv2_run->note;
+    
+    while(note != NULL){
+      //FIXME:JK: ref counting
+      AGS_ROUTE_LV2_AUDIO_RUN(recall_lv2_run->route_lv2_audio_run)->feed_midi = g_list_remove(AGS_ROUTE_LV2_AUDIO_RUN(recall_lv2_run->route_lv2_audio_run)->feed_midi,
+											      note->data);
+      g_object_unref(note->data);
+      
+      note = note->next;
+    }
   }
-  
+
+  g_list_free_full(recall_lv2_run->note,
+		   g_object_unref);
+    
   if(recall_lv2_run->atom_port != NULL){
     free(recall_lv2_run->atom_port);
   }
@@ -421,21 +430,21 @@ ags_recall_lv2_run_run_pre(AgsRecall *recall)
   AgsCountBeatsAudioRun *count_beats_audio_run;
   AgsRouteLv2AudioRun *route_lv2_audio_run;
 
-  AgsMutexManager *mutex_manager;
+  GList *note, *note_next;
   
   guint copy_mode_in, copy_mode_out;
   uint32_t buffer_size;
   uint32_t i;
 
-  pthread_mutex_t *application_mutex;
-  pthread_mutex_t *recycling_mutex;
-
   /* call parent */
   AGS_RECALL_CLASS(ags_recall_lv2_run_parent_class)->run_pre(recall);
 
-  mutex_manager = ags_mutex_manager_get_instance();
-  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
-  
+  if(recall->rt_safe &&
+     recall->recall_id->recycling_context->parent != NULL &&
+     AGS_RECALL_AUDIO_SIGNAL(recall)->source->note == NULL){
+    return;
+  }
+
   recall_lv2 = AGS_RECALL_LV2(AGS_RECALL_CHANNEL_RUN(recall->parent->parent)->recall_channel);
   recall_lv2_run = AGS_RECALL_LV2_RUN(recall);
   
@@ -456,40 +465,46 @@ ags_recall_lv2_run_run_pre(AgsRecall *recall)
   audio_signal = AGS_RECALL_AUDIO_SIGNAL(recall_lv2_run)->source;
   buffer_size = audio_signal->buffer_size;
 
-  if(audio_signal->stream_current == NULL ||
-     (count_beats_audio_run == NULL ||
-      ((AGS_NOTE(recall_lv2_run->note)->x[1] <= count_beats_audio_run->notation_counter &&
-	(AGS_NOTE_FEED & (AGS_NOTE(recall_lv2_run->note)->flags)) == 0) ||
-       AGS_NOTE(recall_lv2_run->note)->x[0] > count_beats_audio_run->notation_counter))){
-    //    g_message("done");
-    /* deactivate */
-    if(recall_lv2->plugin_descriptor->deactivate != NULL){
-      recall_lv2->plugin_descriptor->deactivate(recall_lv2_run->lv2_handle[0]);
+  if(AGS_RECALL(recall_lv2_run)->rt_safe){
+    note = recall_lv2_run->note;
+
+    while(note != NULL){
+      note_next = note->next;
+      
+      if((AGS_NOTE(recall_lv2_run->note->data)->x[1] <= count_beats_audio_run->notation_counter &&
+	  (AGS_NOTE_FEED & (AGS_NOTE(recall_lv2_run->note->data)->flags)) == 0) ||
+	 AGS_NOTE(recall_lv2_run->note->data)->x[0] > count_beats_audio_run->notation_counter){
+	recall_lv2_run->note = g_list_remove(recall_lv2_run->note,
+					     note->data);
+      }
+    
+      note = note_next;
     }
+  }else{
+    if(audio_signal->stream_current == NULL ||
+       (count_beats_audio_run == NULL ||
+	((AGS_NOTE(recall_lv2_run->note->data)->x[1] <= count_beats_audio_run->notation_counter &&
+	  (AGS_NOTE_FEED & (AGS_NOTE(recall_lv2_run->note->data)->flags)) == 0) ||
+	 AGS_NOTE(recall_lv2_run->note->data)->x[0] > count_beats_audio_run->notation_counter))){
+      //    g_message("done");
+      /* deactivate */
+      if(recall_lv2->plugin_descriptor->deactivate != NULL){
+	recall_lv2->plugin_descriptor->deactivate(recall_lv2_run->lv2_handle[0]);
+      }
 
-    /* cleanup */
-    if(recall_lv2->plugin_descriptor->cleanup != NULL){
-      recall_lv2->plugin_descriptor->cleanup(recall_lv2_run->lv2_handle[0]);
-    }
+      /* cleanup */
+      if(recall_lv2->plugin_descriptor->cleanup != NULL){
+	recall_lv2->plugin_descriptor->cleanup(recall_lv2_run->lv2_handle[0]);
+      }
 
-    ags_recall_done(recall);
-    return;
+      ags_recall_done(recall);
+      return;
+    }
   }
-
-  //NOTE:JK: it is safe
+  
   audio_signal = AGS_RECALL_AUDIO_SIGNAL(recall)->source;
 
-  /* lookup recycling mutex */
-  pthread_mutex_lock(application_mutex);
-
-  recycling_mutex = ags_mutex_manager_lookup(mutex_manager,
-					     (GObject *) audio_signal->recycling);
-	
-  pthread_mutex_unlock(application_mutex);
-
   /* get copy mode and clear buffer */
-  pthread_mutex_lock(recycling_mutex);
-
   buffer_size = audio_signal->buffer_size;
 
   copy_mode_in = ags_audio_buffer_util_get_copy_mode(AGS_AUDIO_BUFFER_UTIL_FLOAT,
@@ -516,8 +531,14 @@ ags_recall_lv2_run_run_pre(AgsRecall *recall)
   }
   
   /* process data */
-  recall_lv2->plugin_descriptor->run(recall_lv2_run->lv2_handle[0],
-				     buffer_size);
+  note = recall_lv2_run->note;
+
+  while(note != NULL){
+    recall_lv2->plugin_descriptor->run(recall_lv2_run->lv2_handle[0],
+				       buffer_size);
+
+    note = note->next;
+  }
 
   /* copy data */
   if(recall_lv2_run->output != NULL){
@@ -528,8 +549,6 @@ ags_recall_lv2_run_run_pre(AgsRecall *recall)
 						recall_lv2_run->output, 1, 0,
 						(guint) buffer_size, copy_mode_out);
   }
-
-  pthread_mutex_unlock(recycling_mutex);
 }
 
 void
@@ -546,6 +565,12 @@ ags_recall_lv2_run_run_inter(AgsRecall *recall)
   /* call parent */
   AGS_RECALL_CLASS(ags_recall_lv2_run_parent_class)->run_inter(recall);
 
+  if(recall->rt_safe &&
+     recall->recall_id->recycling_context->parent != NULL &&
+     AGS_RECALL_AUDIO_SIGNAL(recall)->source->note == NULL){
+    return;
+  }
+
   recall_lv2 = AGS_RECALL_LV2(AGS_RECALL_CHANNEL_RUN(recall->parent->parent)->recall_channel);
   recall_lv2_run = AGS_RECALL_LV2_RUN(recall);
   
diff --git a/ags/audio/ags_recall_lv2_run.h b/ags/audio/ags_recall_lv2_run.h
index 139698e..38e3999 100644
--- a/ags/audio/ags_recall_lv2_run.h
+++ b/ags/audio/ags_recall_lv2_run.h
@@ -58,7 +58,7 @@ struct _AgsRecallLv2Run
   unsigned long *event_count;
   
   GObject *route_lv2_audio_run;
-  GObject *note;
+  GList *note;
 
   GObject *worker_handle;
 };
diff --git a/ags/audio/ags_recycling_context.c b/ags/audio/ags_recycling_context.c
index 46c7e03..bb8005b 100644
--- a/ags/audio/ags_recycling_context.c
+++ b/ags/audio/ags_recycling_context.c
@@ -933,9 +933,13 @@ ags_recycling_context_reset_recycling(AgsRecyclingContext *recycling_context,
 
     pthread_mutex_unlock(recycling_mutex);
 
-    new_length = ags_recycling_position(new_first_recycling, next,
-					new_last_recycling);
-    new_length++;
+    if(new_first_recycling != NULL){
+      new_length = ags_recycling_position(new_first_recycling, next,
+					  new_last_recycling);
+      new_length++;
+    }else{
+      new_length = 0;
+    }
   }else{
     new_recycling_context = g_object_new(AGS_TYPE_RECYCLING_CONTEXT,
 					 "length", 0,
@@ -1041,11 +1045,11 @@ ags_recycling_context_reset_recycling(AgsRecyclingContext *recycling_context,
     length = recycling_context->length;
     
     pthread_mutex_unlock(recycling_context->mutex);
-    
+
     new_recycling_context = g_object_new(AGS_TYPE_RECYCLING_CONTEXT,
 					 "length", (length -
-						      (last_index - first_index) +
-						      new_length),
+						    (last_index - first_index + 1) +
+						    new_length),
 					 NULL);
   }
 
diff --git a/ags/audio/ags_wave.c b/ags/audio/ags_wave.c
new file mode 100644
index 0000000..caf6d9b
--- /dev/null
+++ b/ags/audio/ags_wave.c
@@ -0,0 +1,1484 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2018 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/ags_wave.h>
+
+#include <ags/libags.h>
+
+#include <ags/audio/ags_audio.h>
+
+#include <ags/i18n.h>
+
+void ags_wave_class_init(AgsWaveClass *wave);
+void ags_wave_connectable_interface_init(AgsConnectableInterface *connectable);
+void ags_wave_init(AgsWave *wave);
+void ags_wave_set_property(GObject *gobject,
+			   guint prop_id,
+			   const GValue *value,
+			   GParamSpec *param_spec);
+void ags_wave_get_property(GObject *gobject,
+			   guint prop_id,
+			   GValue *value,
+			   GParamSpec *param_spec);
+void ags_wave_connect(AgsConnectable *connectable);
+void ags_wave_disconnect(AgsConnectable *connectable);
+void ags_wave_dispose(GObject *gobject);
+void ags_wave_finalize(GObject *gobject);
+void ags_wave_insert_native_level_from_clipboard(AgsWave *wave,
+						 xmlNode *root_node, char *version,
+						 char *x_boundary,
+						 gboolean reset_x_offset, guint x_offset,
+						 gdouble delay, guint attack,
+						 gboolean match_channel, gboolean do_replace);
+
+/**
+ * SECTION:ags_wave
+ * @short_description: Wave class supporting selection and clipboard.
+ * @title: AgsWave
+ * @section_id:
+ * @include: ags/audio/ags_wave.h
+ *
+ * #AgsWave acts as a container of #AgsBuffer.
+ */
+
+enum{
+  PROP_0,
+  PROP_AUDIO,
+  PROP_AUDIO_CHANNEL,
+  PROP_BUFFER,
+  PROP_TIMESTAMP,
+  PROP_SAMPLERATE,
+  PROP_BUFFER_SIZE,
+  PROP_FORMAT,
+};
+
+static gpointer ags_wave_parent_class = NULL;
+
+GType
+ags_wave_get_type()
+{
+  static GType ags_type_wave = 0;
+
+  if(!ags_type_wave){
+    static const GTypeInfo ags_wave_info = {
+      sizeof(AgsWaveClass),
+      NULL,
+      NULL,
+      (GClassInitFunc) ags_wave_class_init,
+      NULL,
+      NULL,
+      sizeof(AgsWave),
+      0,
+      (GInstanceInitFunc) ags_wave_init,
+    };
+
+    static const GInterfaceInfo ags_connectable_interface_info = {
+      (GInterfaceInitFunc) ags_wave_connectable_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };
+
+    ags_type_wave = g_type_register_static(G_TYPE_OBJECT,
+					   "AgsWave",
+					   &ags_wave_info,
+					   0);
+
+    g_type_add_interface_static(ags_type_wave,
+				AGS_TYPE_CONNECTABLE,
+				&ags_connectable_interface_info);
+  }
+
+  return(ags_type_wave);
+}
+
+void 
+ags_wave_class_init(AgsWaveClass *wave)
+{
+  GObjectClass *gobject;
+  GParamSpec *param_spec;
+
+  ags_wave_parent_class = g_type_class_peek_parent(wave);
+
+  gobject = (GObjectClass *) wave;
+
+  gobject->set_property = ags_wave_set_property;
+  gobject->get_property = ags_wave_get_property;
+
+  gobject->dispose = ags_wave_dispose;
+  gobject->finalize = ags_wave_finalize;
+
+  /* properties */
+  /**
+   * AgsWave:audio:
+   *
+   * The assigned #AgsAudio
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_object("audio",
+				   i18n_pspec("audio of wave"),
+				   i18n_pspec("The audio of wave"),
+				   AGS_TYPE_AUDIO,
+				   G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_AUDIO,
+				  param_spec);
+
+  /**
+   * AgsWave:audio-channel:
+   *
+   * The effect's audio-channel.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec =  g_param_spec_uint("audio-channel",
+				  i18n_pspec("audio-channel of effect"),
+				  i18n_pspec("The numerical audio-channel of effect"),
+				  0,
+				  65535,
+				  0,
+				  G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_AUDIO_CHANNEL,
+				  param_spec);  
+
+  /**
+   * AgsWave:buffer:
+   *
+   * The assigned #AgsBuffer
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_object("buffer",
+				   i18n_pspec("buffer of wave"),
+				   i18n_pspec("The buffer of wave"),
+				   AGS_TYPE_BUFFER,
+				   G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_BUFFER,
+				  param_spec);
+  
+  /**
+   * AgsPattern:timestamp:
+   *
+   * The pattern's timestamp.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_object("timestamp",
+				   i18n_pspec("timestamp of pattern"),
+				   i18n_pspec("The timestamp of pattern"),
+				   AGS_TYPE_TIMESTAMP,
+				   G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_TIMESTAMP,
+				  param_spec);
+
+  /**
+   * AgsWave:samplerate:
+   *
+   * The audio buffer's samplerate.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec =  g_param_spec_uint("samplerate",
+				  i18n_pspec("samplerate of audio buffer"),
+				  i18n_pspec("The samplerate of audio buffer"),
+				  0,
+				  G_MAXUINT,
+				  AGS_SOUNDCARD_DEFAULT_SAMPLERATE,
+				  G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_SAMPLERATE,
+				  param_spec);
+
+  /**
+   * AgsWave:buffer-size:
+   *
+   * The audio buffer's buffer size.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec =  g_param_spec_uint("buffer-size",
+				  i18n_pspec("buffer size of audio buffer"),
+				  i18n_pspec("The buffer size of audio buffer"),
+				  0,
+				  G_MAXUINT,
+				  AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE,
+				  G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_BUFFER_SIZE,
+				  param_spec);
+
+  /**
+   * AgsWave:format:
+   *
+   * The audio buffer's format.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec =  g_param_spec_uint("format",
+				  i18n_pspec("format of audio buffer"),
+				  i18n_pspec("The format of audio buffer"),
+				  0,
+				  G_MAXUINT,
+				  AGS_SOUNDCARD_DEFAULT_FORMAT,
+				  G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_FORMAT,
+				  param_spec);
+}
+
+void
+ags_wave_connectable_interface_init(AgsConnectableInterface *connectable)
+{
+  connectable->is_ready = NULL;
+  connectable->is_connected = NULL;
+  connectable->connect = ags_wave_connect;
+  connectable->disconnect = ags_wave_disconnect;
+}
+
+void
+ags_wave_init(AgsWave *wave)
+{
+  wave->flags = 0;
+
+  wave->timestamp = ags_timestamp_new();
+
+  wave->timestamp->flags &= (~AGS_TIMESTAMP_UNIX);
+  wave->timestamp->flags |= AGS_TIMESTAMP_OFFSET;
+
+  wave->timestamp->timer.ags_offset.offset = 0;
+
+  g_object_ref(wave->timestamp);
+  
+  wave->audio_channel = 0;
+  wave->audio = NULL;
+
+  wave->samplerate = AGS_SOUNDCARD_DEFAULT_SAMPLERATE;
+  wave->buffer_size = AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE;
+  wave->format = AGS_SOUNDCARD_DEFAULT_FORMAT;
+  
+  wave->buffer = NULL;
+
+  wave->loop_start = 0.0;
+  wave->loop_end = 0.0;
+  wave->offset = 0.0;
+
+  wave->selection = NULL;
+}
+
+void
+ags_wave_connect(AgsConnectable *connectable)
+{
+  AgsWave *wave;
+
+  GList *list;
+  
+  wave = AGS_WAVE(connectable);
+
+  if((AGS_WAVE_CONNECTED & (wave->flags)) != 0){
+    return;
+  }
+
+  wave->flags |= AGS_WAVE_CONNECTED;
+
+  /* buffer */
+  list = wave->buffer;
+
+  while(list != NULL){
+    ags_connectable_connect(AGS_CONNECTABLE(list->data));
+
+    list = list->next;
+  }
+}
+
+void
+ags_wave_disconnect(AgsConnectable *connectable)
+{
+  AgsWave *wave;
+
+  GList *list;
+
+  wave = AGS_WAVE(connectable);
+
+  if((AGS_WAVE_CONNECTED & (wave->flags)) == 0){
+    return;
+  }
+
+  wave->flags &= (~AGS_WAVE_CONNECTED);
+
+  /* buffer */
+  list = wave->buffer;
+
+  while(list != NULL){
+    ags_connectable_disconnect(AGS_CONNECTABLE(list->data));
+
+    list = list->next;
+  }
+}
+
+void
+ags_wave_set_property(GObject *gobject,
+		      guint prop_id,
+		      const GValue *value,
+		      GParamSpec *param_spec)
+{
+  AgsWave *wave;
+
+  wave = AGS_WAVE(gobject);
+
+  switch(prop_id){
+  case PROP_AUDIO:
+    {
+      AgsAudio *audio;
+
+      audio = (AgsAudio *) g_value_get_object(value);
+
+      if(wave->audio == (GObject *) audio){
+	return;
+      }
+
+      if(wave->audio != NULL){
+	g_object_unref(wave->audio);
+      }
+
+      if(audio != NULL){
+	g_object_ref(audio);
+      }
+
+      wave->audio = (GObject *) audio;
+    }
+    break;
+  case PROP_AUDIO_CHANNEL:
+    {
+      guint audio_channel;
+
+      audio_channel = g_value_get_uint(value);
+
+      wave->audio_channel = audio_channel;
+    }
+    break;
+  case PROP_BUFFER:
+    {
+      AgsBuffer *buffer;
+
+      buffer = (AgsBuffer *) g_value_get_object(value);
+
+      if(buffer == NULL ||
+	 g_list_find(wave->buffer, buffer) != NULL){
+	return;
+      }
+
+      ags_wave_add_buffer(wave,
+			  buffer,
+			  FALSE);
+    }
+    break;
+  case PROP_TIMESTAMP:
+    {
+      AgsTimestamp *timestamp;
+
+      timestamp = (AgsTimestamp *) g_value_get_object(value);
+
+      if(timestamp == (AgsTimestamp *) wave->timestamp){
+	return;
+      }
+
+      if(wave->timestamp != NULL){
+	g_object_unref(G_OBJECT(wave->timestamp));
+      }
+
+      if(timestamp != NULL){
+	g_object_ref(G_OBJECT(timestamp));
+      }
+
+      wave->timestamp = (GObject *) timestamp;
+    }
+    break;
+  case PROP_SAMPLERATE:
+    {
+      guint samplerate;
+
+      samplerate = g_value_get_uint(value);
+
+      ags_wave_set_samplerate(wave,
+			      samplerate);
+    }
+    break;
+  case PROP_BUFFER_SIZE:
+    {
+      guint buffer_size;
+
+      buffer_size = g_value_get_uint(value);
+
+      ags_wave_set_buffer_size(wave,
+			       buffer_size);
+    }
+    break;
+  case PROP_FORMAT:
+    {
+      guint format;
+
+      format = g_value_get_uint(value);
+
+      ags_wave_set_format(wave,
+			  format);
+    }
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
+    break;
+  }
+}
+
+void
+ags_wave_get_property(GObject *gobject,
+		      guint prop_id,
+		      GValue *value,
+		      GParamSpec *param_spec)
+{
+  AgsWave *wave;
+
+  wave = AGS_WAVE(gobject);
+
+  switch(prop_id){
+  case PROP_AUDIO:
+    {
+      g_value_set_object(value, wave->audio);
+    }
+    break;
+  case PROP_AUDIO_CHANNEL:
+    {
+      g_value_set_uint(value, wave->audio_channel);
+    }
+    break;
+  case PROP_TIMESTAMP:
+    {
+      g_value_set_object(value, wave->timestamp);
+    }
+    break;
+  case PROP_SAMPLERATE:
+    {
+      g_value_set_uint(value, wave->samplerate);
+    }
+    break;
+  case PROP_BUFFER_SIZE:
+    {
+      g_value_set_uint(value, wave->buffer_size);
+    }
+    break;
+  case PROP_FORMAT:
+    {
+      g_value_set_uint(value, wave->format);
+    }
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
+    break;
+  }
+}
+
+void
+ags_wave_dispose(GObject *gobject)
+{
+  AgsWave *wave;
+
+  GList *list;
+  
+  wave = AGS_WAVE(gobject);
+
+  /* timestamp */
+  if(wave->timestamp != NULL){
+    g_object_unref(wave->timestamp);
+
+    wave->timestamp = NULL;
+  }
+
+  /* audio */
+  if(wave->audio != NULL){
+    g_object_unref(wave->audio);
+
+    wave->audio = NULL;
+  }
+
+    
+  /* buffer and selection */
+  list = wave->buffer;
+
+  while(list != NULL){
+    g_object_run_dispose(G_OBJECT(list->data));
+    
+    list = list->next;
+  }
+  
+  g_list_free_full(wave->buffer,
+		   g_object_unref);
+
+  g_list_free(wave->selection);
+
+  wave->buffer = NULL;
+  wave->selection = NULL;
+    
+  /* call parent */
+  G_OBJECT_CLASS(ags_wave_parent_class)->dispose(gobject);
+}
+
+void
+ags_wave_finalize(GObject *gobject)
+{
+  AgsWave *wave;
+
+  wave = AGS_WAVE(gobject);
+
+  /* timestamp */
+  if(wave->timestamp != NULL){
+    g_object_unref(wave->timestamp);
+  }
+
+  /* audio */
+  if(wave->audio != NULL){
+    g_object_unref(wave->audio);
+  }
+    
+  /* buffer and selection */
+  g_list_free_full(wave->buffer,
+		   g_object_unref);
+
+  g_list_free(wave->selection);
+  
+  /* call parent */
+  G_OBJECT_CLASS(ags_wave_parent_class)->finalize(gobject);
+}
+
+/**
+ * ags_wave_set_samplerate:
+ * @wave: the #AgsWave
+ * @samplerate: the samplerate
+ * 
+ * Set samplerate. 
+ * 
+ * Since: 1.4.0
+ */
+void
+ags_wave_set_samplerate(AgsWave *wave,
+			guint samplerate)
+{
+  GList *list;
+
+  wave->samplerate = samplerate;
+
+  list = wave->buffer;
+  
+  while(list != NULL){
+    ags_buffer_set_samplerate(list->data,
+			      samplerate);
+
+    list = list->next;
+  }
+}
+
+/**
+ * ags_wave_set_buffer_size:
+ * @wave: the #AgsWave
+ * 
+ * Set buffer size.
+ * 
+ * Since: 1.4.0
+ */
+void
+ags_wave_set_buffer_size(AgsWave *wave,
+			 guint buffer_size)
+{
+  GList *list;
+
+  wave->buffer_size = buffer_size;
+
+  list = wave->buffer;
+  
+  while(list != NULL){
+    ags_buffer_set_buffer_size(list->data,
+			       buffer_size);
+
+    list = list->next;
+  }
+}
+
+/**
+ * ags_wave_set_format:
+ * @wave: the #AgsWave
+ * @format: the format
+ * 
+ * Set format. 
+ * 
+ * Since: 1.4.0
+ */
+void
+ags_wave_set_format(AgsWave *wave,
+		    guint format)
+{
+  GList *list;
+
+  wave->format = format;
+
+  list = wave->buffer;
+  
+  while(list != NULL){
+    ags_buffer_set_format(list->data,
+			  format);
+
+    list = list->next;
+  }
+}
+
+/**
+ * ags_wave_find_near_timestamp:
+ * @wave: a #GList containing #AgsWave
+ * @audio_channel: the matching audio channel
+ * @timestamp: (allow-none): the matching timestamp, or %NULL to match any timestamp
+ *
+ * Retrieve appropriate wave for timestamp.
+ *
+ * Returns: Next match.
+ *
+ * Since: 1.4.0
+ */
+GList*
+ags_wave_find_near_timestamp(GList *wave, guint audio_channel,
+			     AgsTimestamp *timestamp)
+{
+  AgsTimestamp *current_timestamp;
+
+  while(wave != NULL){
+    if(AGS_WAVE(wave->data)->audio_channel != audio_channel){
+      wave = wave->next;
+      
+      continue;
+    }
+
+    if(timestamp == NULL){
+      return(wave);
+    }
+    
+    current_timestamp = (AgsTimestamp *) AGS_WAVE(wave->data)->timestamp;
+
+    if(current_timestamp != NULL){
+      if((AGS_TIMESTAMP_UNIX & (timestamp->flags)) != 0 &&
+	 (AGS_TIMESTAMP_UNIX & (current_timestamp->flags)) != 0){
+	if(current_timestamp->timer.unix_time.time_val >= timestamp->timer.unix_time.time_val &&
+	   current_timestamp->timer.unix_time.time_val < timestamp->timer.unix_time.time_val + AGS_WAVE_DEFAULT_DURATION){
+	  return(wave);
+	}
+      }else if((AGS_TIMESTAMP_OFFSET & (timestamp->flags)) != 0 &&
+	       (AGS_TIMESTAMP_OFFSET & (current_timestamp->flags)) != 0){
+	if(current_timestamp->timer.ags_offset.offset >= timestamp->timer.ags_offset.offset &&
+	   current_timestamp->timer.ags_offset.offset < timestamp->timer.ags_offset.offset + AGS_WAVE_DEFAULT_OFFSET){
+	  return(wave);
+	}
+      }
+    }
+    
+    wave = wave->next;
+  }
+  
+  return(NULL);
+}
+
+/**
+ * ags_wave_add:
+ * @wave: the #GList-struct containing #AgsWave
+ * @new_wave: the wave to add
+ * 
+ * Add @new_wave sorted to @wave
+ * 
+ * Returns: the new beginning of @wave
+ * 
+ * Since: 1.4.0
+ */
+GList*
+ags_wave_add(GList *wave,
+	     AgsWave *new_wave)
+{
+  auto gint ags_wave_add_compare(gconstpointer a,
+				 gconstpointer b);
+  
+  gint ags_wave_add_compare(gconstpointer a,
+			    gconstpointer b)
+  {
+    if(AGS_WAVE(a)->timestamp->timer.ags_offset.offset == AGS_WAVE(b)->timestamp->timer.ags_offset.offset){
+      return(0);
+    }else if(AGS_WAVE(a)->timestamp->timer.ags_offset.offset < AGS_WAVE(b)->timestamp->timer.ags_offset.offset){
+      return(-1);
+    }else if(AGS_WAVE(a)->timestamp->timer.ags_offset.offset > AGS_WAVE(b)->timestamp->timer.ags_offset.offset){
+      return(1);
+    }
+
+    return(0);
+  }
+  
+  if(!AGS_IS_WAVE(new_wave) ||
+     !AGS_IS_TIMESTAMP(new_wave->timestamp)){
+    return(wave);
+  }
+  
+  wave = g_list_insert_sorted(wave,
+			      new_wave,
+			      ags_wave_add_compare);
+  
+  return(wave);
+}
+
+/**
+ * ags_wave_add_buffer:
+ * @wave: an #AgsWave
+ * @buffer: the #AgsBuffer to add
+ * @use_selection_list: if %TRUE add to selection, else to default wave
+ *
+ * Adds a buffer to wave.
+ *
+ * Since: 1.4.0
+ */
+void
+ags_wave_add_buffer(AgsWave *wave,
+		    AgsBuffer *buffer,
+		    gboolean use_selection_list)
+{
+  if(!AGS_IS_WAVE(wave) ||
+     !AGS_IS_BUFFER(buffer)){
+    return;
+  }
+
+  g_object_ref(buffer);
+  
+  if(use_selection_list){
+    wave->selection = g_list_insert_sorted(wave->selection,
+					   buffer,
+					   (GCompareFunc) ags_buffer_sort_func);
+  }else{
+    wave->buffer = g_list_insert_sorted(wave->buffer,
+					buffer,
+					(GCompareFunc) ags_buffer_sort_func);
+  }
+}
+
+/**
+ * ags_wave_remove_buffer:
+ * @wave: an #AgsWave
+ * @buffer: the #AgsBuffer to remove
+ * @use_selection_list: if %TRUE remove from selection, else from default wave
+ *
+ * Removes a buffer from wave.
+ *
+ * Since: 1.4.0
+ */
+void
+ags_wave_remove_buffer(AgsWave *wave,
+		       AgsBuffer *buffer,
+		       gboolean use_selection_list)
+{
+  if(!AGS_IS_WAVE(wave) ||
+     !AGS_IS_BUFFER(buffer)){
+    return;
+  }
+  
+  if(!use_selection_list){
+    wave->buffer = g_list_remove(wave->buffer,
+				 buffer);
+  }else{
+    wave->selection = g_list_remove(wave->selection,
+				    buffer);
+  }
+}
+
+/**
+ * ags_wave_get_selection:
+ * @wave: the #AgsWave
+ *
+ * Retrieve selection.
+ *
+ * Returns: the selection.
+ *
+ * Since: 1.4.0
+ */
+GList*
+ags_wave_get_selection(AgsWave *wave)
+{
+  return(wave->selection);
+}
+
+/**
+ * ags_wave_is_buffer_selected:
+ * @wave: the #AgsWave
+ * @buffer: the #AgsBuffer to check for
+ *
+ * Check selection for buffer.
+ *
+ * Returns: %TRUE if selected
+ *
+ * Since: 1.4.0
+ */
+gboolean
+ags_wave_is_buffer_selected(AgsWave *wave, AgsBuffer *buffer)
+{
+  GList *selection;
+
+  selection = wave->selection;
+
+  while(selection != NULL && AGS_BUFFER(selection->data)->x <= buffer->x){
+    if(selection->data == buffer){
+      return(TRUE);
+    }
+
+    selection = selection->next;
+  }
+
+  return(FALSE);
+}
+
+/**
+ * ags_wave_find_region:
+ * @wave: an #AgsWave
+ * @x0: start offset
+ * @x1: end offset
+ * @use_selection_list: if %TRUE selection is searched
+ *
+ * Find buffers by offset and tone region.
+ *
+ * Returns: the matching buffers as #GList.
+ *
+ * Since: 1.4.0
+ */
+GList*
+ags_wave_find_region(AgsWave *wave,
+		     guint x0,
+		     guint x1,
+		     gboolean use_selection_list)
+{
+  AgsBuffer *buffer;
+  
+  GList *buffer_list;
+  GList *region;
+
+  if(x0 > x1){
+    guint tmp;
+
+    tmp = x1;
+    x1 = x0;
+    x0 = x1;
+  }
+    
+  if(use_selection_list){
+    buffer_list = wave->selection;
+  }else{
+    buffer_list = wave->buffer;
+  }
+
+  while(buffer_list != NULL && AGS_BUFFER(buffer_list->data)->x < x0){
+    buffer_list = buffer_list->next;
+  }
+
+  region = NULL;
+
+  while(buffer_list != NULL && (buffer = AGS_BUFFER(buffer_list->data))->x < x1){
+    region = g_list_prepend(region, buffer);
+
+    buffer_list = buffer_list->next;
+  }
+
+  region = g_list_reverse(region);
+
+  return(region);
+}
+
+/**
+ * ags_wave_free_selection:
+ * @wave: an #AgsWave
+ *
+ * Clear selection.
+ *
+ * Since: 1.4.0
+ */
+void
+ags_wave_free_selection(AgsWave *wave)
+{
+  g_list_free_full(wave->selection,
+		   g_object_unref);
+  
+  wave->selection = NULL;
+}
+
+/**
+ * ags_wave_add_all_to_selection:
+ * @wave: an #AgsWave
+ *
+ * Select all.
+ *
+ * Since: 1.4.0
+ */
+void
+ags_wave_add_all_to_selection(AgsWave *wave)
+{
+  AgsBuffer *buffer;
+  GList *region, *list;
+
+  ags_wave_free_selection(wave);
+  list = wave->buffer;
+  
+  while(list != NULL){
+    AGS_BUFFER(list->data)->flags |= AGS_BUFFER_IS_SELECTED;
+    g_object_ref(G_OBJECT(list->data));
+    
+    list = list->next;
+  }
+
+  wave->selection = g_list_copy(wave->buffer);
+}
+
+/**
+ * ags_wave_add_region_to_selection:
+ * @wave: an #AgsWave
+ * @x0: start offset
+ * @x1: end offset
+ * @replace_current_selection: if %TRUE selection is replaced
+ *
+ * Select buffers within region.
+ *
+ * Since: 1.4.0
+ */
+void
+ags_wave_add_region_to_selection(AgsWave *wave,
+				 guint x0, guint x1,
+				 gboolean replace_current_selection)
+{
+  AgsBuffer *buffer;
+
+  GList *region, *list;
+
+  region = ags_wave_find_region(wave,
+				x0,
+				x1,
+				FALSE);
+
+  if(replace_current_selection){
+    ags_wave_free_selection(wave);
+
+    list = region;
+
+    while(list != NULL){
+      AGS_BUFFER(list->data)->flags |= AGS_BUFFER_IS_SELECTED;
+      g_object_ref(G_OBJECT(list->data));
+
+      list = list->next;
+    }
+
+    wave->selection = region;
+  }else{
+    while(region != NULL){
+      buffer = AGS_BUFFER(region->data);
+
+      if(!ags_wave_is_buffer_selected(wave, buffer)){
+	buffer->flags |= AGS_BUFFER_IS_SELECTED;
+	g_object_ref(G_OBJECT(buffer));
+	ags_wave_add_buffer(wave,
+			    buffer,
+			    TRUE);
+      }
+      
+      region = region->next;
+    }
+    
+    g_list_free(region);
+  }
+}
+
+/**
+ * ags_wave_remove_region_from_selection:
+ * @wave: an #AgsWave
+ * @x0: start offset
+ * @y0: start tone
+ * @x1: end offset
+ * @y1: end tone
+ *
+ * Remove buffers within region of selection.
+ *
+ * Since: 1.4.0
+ */ 
+void
+ags_wave_remove_region_from_selection(AgsWave *wave,
+				      guint x0, guint x1)
+{
+  AgsBuffer *buffer;
+  
+  GList *region;
+
+  region = ags_wave_find_region(wave,
+				x0,
+				x1,
+				TRUE);
+
+  while(region != NULL){
+    buffer = AGS_BUFFER(region->data);
+    buffer->flags &= (~AGS_BUFFER_IS_SELECTED);
+
+    wave->selection = g_list_remove(wave->selection, buffer);
+    g_object_unref(G_OBJECT(buffer));
+
+    region = region->next;
+  }
+
+  g_list_free(region);
+}
+
+/**
+ * ags_wave_copy_selection:
+ * @wave: an #AgsWave
+ *
+ * Copy selection to clipboard.
+ *
+ * Returns: the selection as XML.
+ *
+ * Since: 1.4.0
+ */
+xmlNode*
+ags_wave_copy_selection(AgsWave *wave)
+{
+  AgsBuffer *buffer;
+
+  xmlNode *wave_node, *current_buffer;
+  xmlNode *timestamp_node;
+
+  GList *selection;
+
+  xmlChar *str;
+  
+  guint x_boundary, y_boundary;
+
+  selection = wave->selection;
+
+  /* create root node */
+  wave_node = xmlNewNode(NULL,
+			 BAD_CAST "wave");
+
+  xmlNewProp(wave_node,
+	     BAD_CAST "program",
+	     BAD_CAST "ags");
+  xmlNewProp(wave_node,
+	     BAD_CAST "type",
+	     BAD_CAST (AGS_WAVE_CLIPBOARD_TYPE));
+  xmlNewProp(wave_node,
+	     BAD_CAST "version",
+	     BAD_CAST (AGS_WAVE_CLIPBOARD_VERSION));
+  xmlNewProp(wave_node,
+	     BAD_CAST "format",
+	     BAD_CAST (AGS_WAVE_CLIPBOARD_FORMAT));
+  xmlNewProp(wave_node,
+	     BAD_CAST "audio-channel",
+	     BAD_CAST (g_strdup_printf("%u", wave->audio_channel)));
+
+  /* buffer format */
+  str = NULL;
+  
+  switch(wave->format){    
+  case AGS_SOUNDCARD_SIGNED_8_BIT:
+    {
+      str = "s8";
+    }
+    break;
+  case AGS_SOUNDCARD_SIGNED_16_BIT:
+    {
+      str = "s16";
+    }
+    break;
+  case AGS_SOUNDCARD_SIGNED_24_BIT:
+    {
+      str = "s24";
+    }
+    break;
+  case AGS_SOUNDCARD_SIGNED_32_BIT:
+    {
+      str = "s32";
+    }
+    break;
+  case AGS_SOUNDCARD_SIGNED_64_BIT:
+    {
+      str = "s64";
+    }
+    break;
+  }
+
+  xmlNewProp(wave_node,
+	     BAD_CAST "buffer-format",
+	     BAD_CAST (str));
+  
+  /* timestamp */
+  if(wave->timestamp != NULL){
+    timestamp_node = xmlNewNode(NULL,
+				BAD_CAST "timestamp");
+    xmlAddChild(wave_node,
+		timestamp_node);
+
+    xmlNewProp(timestamp_node,
+	       BAD_CAST "offset",
+	       BAD_CAST (g_strdup_printf("%u", AGS_TIMESTAMP(wave->timestamp)->timer.ags_offset.offset)));
+  }
+  
+  /* selection */
+  selection = wave->selection;
+
+  if(selection != NULL){
+    x_boundary = AGS_BUFFER(selection->data)->x;
+  }else{
+    x_boundary = 0;
+  }
+
+  while(selection != NULL){
+    xmlChar *content;
+    unsigned char *cbuffer;
+
+    guint buffer_size;
+    
+    buffer = AGS_BUFFER(selection->data);
+    current_buffer = xmlNewChild(wave_node,
+			       NULL,
+			       BAD_CAST "buffer",
+			       NULL);
+
+    xmlNewProp(current_buffer,
+	       BAD_CAST "x",
+	       BAD_CAST (g_strdup_printf("%u", buffer->x)));
+
+    xmlNewProp(current_buffer,
+	       BAD_CAST "selection-x0",
+	       BAD_CAST (g_strdup_printf("%u", buffer->selection_x0)));
+
+    xmlNewProp(current_buffer,
+	       BAD_CAST "selection-x1",
+	       BAD_CAST (g_strdup_printf("%u", buffer->selection_x1)));
+    
+    cbuffer = NULL;
+    buffer_size = 0;
+    
+    switch(buffer->format){
+    case AGS_SOUNDCARD_SIGNED_8_BIT:
+      {
+	cbuffer = ags_buffer_util_s8_to_char_buffer((signed char *) buffer->data,
+						    buffer->buffer_size);
+	buffer_size = buffer->buffer_size;
+      }
+      break;
+    case AGS_SOUNDCARD_SIGNED_16_BIT:
+      {
+	cbuffer = ags_buffer_util_s16_to_char_buffer((signed short *) buffer->data,
+						     buffer->buffer_size);
+	buffer_size = 2 * buffer->buffer_size;
+      }
+      break;
+    case AGS_SOUNDCARD_SIGNED_24_BIT:
+      {
+	cbuffer = ags_buffer_util_s24_to_char_buffer((signed long *) buffer->data,
+						     buffer->buffer_size);
+	buffer_size = 3 * buffer->buffer_size;
+      }
+      break;
+    case AGS_SOUNDCARD_SIGNED_32_BIT:
+      {
+	cbuffer = ags_buffer_util_s32_to_char_buffer((signed long *) buffer->data,
+						     buffer->buffer_size);
+	buffer_size = 4 * buffer->buffer_size;
+      }
+      break;
+    case AGS_SOUNDCARD_SIGNED_64_BIT:
+      {
+	cbuffer = ags_buffer_util_s64_to_char_buffer((signed long long *) buffer->data,
+						     buffer->buffer_size);
+	buffer_size = 8 * buffer->buffer_size;
+      }
+      break;
+    }
+    
+    xmlNodeSetContent(current_buffer,
+		      g_base64_encode(cbuffer,
+				      buffer_size));
+    
+    g_free(cbuffer);
+    
+    selection = selection->next;
+  }
+
+  xmlNewProp(wave_node,
+	     BAD_CAST "x-boundary",
+	     BAD_CAST (g_strdup_printf("%u", x_boundary)));
+
+  return(wave_node);
+
+  return(NULL);
+}
+
+/**
+ * ags_wave_cut_selection:
+ * @wave: an #AgsWave
+ *
+ * Cut selection to clipboard.
+ *
+ * Returns: the selection as XML.
+ *
+ * Since: 1.4.0
+ */
+xmlNode*
+ags_wave_cut_selection(AgsWave *wave)
+{
+  xmlNode* wave_node;
+
+  GList *selection;
+  
+  wave_node = ags_wave_copy_selection(wave);
+
+  selection = wave->selection;
+
+  while(selection != NULL){
+    wave->buffer = g_list_remove(wave->buffer,
+				 selection->data);
+    
+    AGS_BUFFER(selection->data)->flags &= (~AGS_BUFFER_IS_SELECTED);
+    g_object_unref(selection->data);
+
+    selection = selection->next;
+  }
+
+  ags_wave_free_selection(wave);
+
+  return(wave_node);
+}
+
+/**
+ * ags_wave_insert_native_level_from_clipboard:
+ * @wave: an #AgsWave
+ * @wave_node: the clipboard XML data
+ * @version: clipboard version
+ * @x_boundary: region start offset
+ * @reset_x_offset: if %TRUE @x_offset used as cursor
+ * @x_offset: region start cursor offset
+ * @delay: the delay to be used
+ * @attack: the attack to be used
+ * @match_channel: only paste if channel matches
+ * @do_replace: if %TRUE current data is replaced, otherwise additive mixing is performed 
+ *
+ * Paste previously copied buffers. 
+ *
+ * Since: 1.4.0
+ */
+void
+ags_wave_insert_native_level_from_clipboard(AgsWave *wave,
+					    xmlNode *root_node, char *version,
+					    char *x_boundary,
+					    gboolean reset_x_offset, guint x_offset,
+					    gdouble delay, guint attack,
+					    gboolean match_channel, gboolean do_replace)
+{
+  auto void ags_wave_insert_native_level_from_clipboard_version_1_4_0();
+  
+  void ags_wave_insert_native_level_from_clipboard_version_1_4_0()
+  {
+    AgsBuffer *buffer;
+
+    xmlNode *node;
+
+    char *x;
+    gchar *offset;
+    char *endptr;
+
+    guint x_boundary_val;
+    guint x_val;
+    guint base_x_difference;
+    guint offset_val;
+    gboolean subtract_x;
+
+    node = root_node->children;
+
+    /* retrieve x values for resetting */
+    if(reset_x_offset){
+      if(x_boundary != NULL){
+	errno = 0;
+	x_boundary_val = strtoul(x_boundary,
+				 &endptr,
+				 10);
+
+	if(errno == ERANGE){
+	  goto dont_reset_x_offset;
+	} 
+	
+	if(x_boundary == endptr){
+	  goto dont_reset_x_offset;
+	}
+
+	if(x_boundary_val < x_offset){
+	  base_x_difference = x_offset - x_boundary_val;
+	  subtract_x = FALSE;
+	}else{
+	  base_x_difference = x_boundary_val - x_offset;
+	  subtract_x = TRUE;
+	}
+      }else{
+      dont_reset_x_offset:
+	reset_x_offset = FALSE;
+      }
+    }
+
+    /* parse */
+    while(node != NULL){
+      if(node->type == XML_ELEMENT_NODE){
+	if(!xmlStrncmp("buffer",
+		       node->name,
+		       7)){
+	  //TODO:JK: implement me
+	}else if(!xmlStrncmp("timestamp",
+			     node->name,
+			     10)){
+	  //TODO:JK: implement me
+	}
+      }
+      
+      node = node->next;
+    }
+  }
+
+  if(!AGS_IS_WAVE(wave)){
+    return;
+  }
+  
+  if(!xmlStrncmp("1.4.0", version, 7)){
+    /* changes contain only optional informations */
+    if(match_channel &&
+       wave->audio_channel != g_ascii_strtoull(xmlGetProp(root_node,
+							      "audio-channel"),
+						   NULL,
+						   10)){
+      return;
+    }
+    
+    ags_wave_insert_native_level_from_clipboard_version_1_4_0();
+  }  
+}
+
+/**
+ * ags_wave_insert_from_clipboard:
+ * @wave: an #AgsWave
+ * @wave_node: the clipboard XML data
+ * @reset_x_offset: if %TRUE @x_offset used as cursor
+ * @x_offset: region start cursor offset
+ * @delay: the delay to be used
+ * @attack: the attack to be used
+ *
+ * Paste previously copied buffers. 
+ *
+ * Since: 1.4.0
+ */
+void
+ags_wave_insert_from_clipboard(AgsWave *wave,
+			       xmlNode *wave_node,
+			       gboolean reset_x_offset, guint x_offset,
+			       gdouble delay, guint attack)
+{
+  ags_wave_insert_from_clipboard_extended(wave,
+					  wave_node,
+					  reset_x_offset, x_offset,
+					  delay, attack,
+					  FALSE, FALSE);
+}
+
+/**
+ * ags_wave_insert_from_clipboard_extended:
+ * @wave: an #AgsWave
+ * @wave_node: the clipboard XML data
+ * @reset_x_offset: if %TRUE @x_offset used as cursor
+ * @x_offset: region start cursor offset
+ * @delay: the delay to be used
+ * @attack: the attack to be used
+ * @match_channel: only paste if channel matches
+ * @do_replace: if %TRUE current data is replaced, otherwise additive mixing is performed 
+ * 
+ * Paste previously copied buffers. 
+ * 
+ * Since: 1.4.0
+ */
+void
+ags_wave_insert_from_clipboard_extended(AgsWave *wave,
+					xmlNode *wave_node,
+					gboolean reset_x_offset, guint x_offset,
+					gdouble delay, guint attack,
+					gboolean match_audio_channel, gboolean do_replace)
+{
+  char *program, *version, *type, *format;
+  char *x_boundary;
+
+  while(wave_node != NULL){
+    if(wave_node->type == XML_ELEMENT_NODE && !xmlStrncmp("wave", wave_node->name, 9)){
+      break;
+    }
+
+    wave_node = wave_node->next;
+  }
+
+  if(wave_node != NULL){
+    program = xmlGetProp(wave_node, "program");
+
+    if(!xmlStrncmp("ags", program, 4)){
+      version = xmlGetProp(wave_node, "version");
+      type = xmlGetProp(wave_node, "type");
+      format = xmlGetProp(wave_node, "format");
+
+      if(!xmlStrcmp(AGS_WAVE_CLIPBOARD_FORMAT,
+		    format)){
+	x_boundary = xmlGetProp(wave_node, "x_boundary");
+
+	ags_wave_insert_native_level_from_clipboard(wave,
+						    wave_node, version,
+						    x_boundary,
+						    reset_x_offset, x_offset,
+						    delay, attack,
+						    match_audio_channel, do_replace);
+      }
+    }
+  }
+}
+
+/**
+ * ags_wave_new:
+ * @audio: the assigned #AgsAudio
+ * @audio_channel: the audio channel to be used
+ *
+ * Creates a #AgsWave, assigned to @audio_channel.
+ *
+ * Returns: a new #AgsWave
+ *
+ * Since: 1.4.0
+ */
+AgsWave*
+ags_wave_new(GObject *audio,
+	     guint audio_channel)
+{
+  AgsWave *wave;
+  
+  wave = (AgsWave *) g_object_new(AGS_TYPE_WAVE,
+				  "audio", audio,
+				  "audio-channel", audio_channel,
+				  NULL);
+  
+  return(wave);
+}
diff --git a/ags/audio/ags_wave.h b/ags/audio/ags_wave.h
new file mode 100644
index 0000000..81d2429
--- /dev/null
+++ b/ags/audio/ags_wave.h
@@ -0,0 +1,154 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2018 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_WAVE_H__
+#define __AGS_WAVE_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libxml/tree.h>
+
+#include <ags/libags.h>
+
+#include <ags/audio/ags_buffer.h>
+
+#define AGS_TYPE_WAVE                (ags_wave_get_type())
+#define AGS_WAVE(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_WAVE, AgsWave))
+#define AGS_WAVE_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_WAVE, AgsWaveClass))
+#define AGS_IS_WAVE(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AGS_TYPE_WAVE))
+#define AGS_IS_WAVE_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_WAVE))
+#define AGS_WAVE_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS (obj, AGS_TYPE_WAVE, AgsWaveClass))
+
+#define AGS_WAVE_DEFAULT_BPM (120.0)
+
+#define AGS_WAVE_TICS_PER_BEAT (1.0)
+#define AGS_WAVE_MINIMUM_BUFFER_LENGTH (1.0 / 16.0)
+
+#define AGS_WAVE_DEFAULT_LENGTH (65535.0 / AGS_WAVE_TICS_PER_BEAT - AGS_WAVE_MINIMUM_BUFFER_LENGTH)
+#define AGS_WAVE_DEFAULT_JIFFIE (60.0 / AGS_WAVE_DEFAULT_BPM / AGS_WAVE_TICS_PER_BEAT)
+#define AGS_WAVE_DEFAULT_DURATION (AGS_WAVE_DEFAULT_LENGTH * AGS_WAVE_DEFAULT_JIFFIE * AGS_MICROSECONDS_PER_SECOND)
+#define AGS_WAVE_DEFAULT_OFFSET (64 * (1 / AGS_WAVE_MINIMUM_BUFFER_LENGTH))
+
+#define AGS_WAVE_CLIPBOARD_VERSION "1.4.0"
+#define AGS_WAVE_CLIPBOARD_TYPE "AgsWaveClipboardXml"
+#define AGS_WAVE_CLIPBOARD_FORMAT "AgsWaveNativeLevel"
+
+typedef struct _AgsWave AgsWave;
+typedef struct _AgsWaveClass AgsWaveClass;
+
+/**
+ * AgsWaveFlags:
+ * @AGS_WAVE_CONNECTED: indicates the wave was connected by calling #AgsConnectable::connect()
+ * 
+ * Enum values to control the behavior or indicate internal state of #AgsWave by
+ * enable/disable as flags.
+ */
+typedef enum{
+  AGS_WAVE_CONNECTED            = 1,
+}AgsWaveFlags;
+
+struct _AgsWave
+{
+  GObject gobject;
+
+  guint flags;
+
+  AgsTimestamp *timestamp;
+
+  GObject *audio;
+  guint audio_channel;
+
+  guint samplerate;
+  guint buffer_size;
+  guint format;
+  
+  GList *buffer;
+
+  gdouble loop_start;
+  gdouble loop_end;
+  gdouble offset;
+  
+  GList *selection;
+};
+
+struct _AgsWaveClass
+{
+  GObjectClass gobject;
+};
+
+GType ags_wave_get_type(void);
+
+void ags_wave_set_samplerate(AgsWave *wave,
+			     guint samplerate);
+void ags_wave_set_buffer_size(AgsWave *wave,
+			      guint buffer_size);
+void ags_wave_set_format(AgsWave *wave,
+			 guint format);
+
+GList* ags_wave_find_near_timestamp(GList *wave, guint audio_channel,
+				    AgsTimestamp *timestamp);
+
+GList* ags_wave_add(GList *wave,
+		    AgsWave *new_wave);
+
+void ags_wave_add_buffer(AgsWave *wave,
+			 AgsBuffer *buffer,
+			 gboolean use_selection_list);
+void ags_wave_remove_buffer(AgsWave *wave,
+			    AgsBuffer *buffer,
+			    gboolean use_selection_list);
+
+GList* ags_wave_get_selection(AgsWave *wave);
+
+gboolean ags_wave_is_buffer_selected(AgsWave *wave, AgsBuffer *buffer);
+
+GList* ags_wave_find_region(AgsWave *wave,
+			    guint x0,
+			    guint x1,
+			    gboolean use_selection_list);
+
+void ags_wave_free_selection(AgsWave *wave);
+
+void ags_wave_add_region_to_selection(AgsWave *wave,
+				      guint x0, guint x1,
+				      gboolean replace_current_selection);
+void ags_wave_remove_region_from_selection(AgsWave *wave,
+					   guint x0, guint x1);
+
+void ags_wave_add_all_to_selection(AgsWave *wave);
+
+xmlNode* ags_wave_copy_selection(AgsWave *wave);
+xmlNode* ags_wave_cut_selection(AgsWave *wave);
+
+void ags_wave_insert_from_clipboard(AgsWave *wave,
+				    xmlNode *wave_node,
+				    gboolean reset_x_offset, guint x_offset,
+				    gdouble delay, guint attack);
+
+void ags_wave_insert_from_clipboard_extended(AgsWave *wave,
+					     xmlNode *wave_node,
+					     gboolean reset_x_offset, guint x_offset,
+					     gdouble delay, guint attack,
+					     gboolean match_audio_channel, gboolean do_replace);
+
+AgsWave* ags_wave_new(GObject *audio,
+		      guint audio_channel);
+
+#endif /*__AGS_WAVE_H__*/
diff --git a/ags/audio/pulse/ags_pulse_port.c b/ags/audio/pulse/ags_pulse_port.c
index 216a32b..08bbda2 100644
--- a/ags/audio/pulse/ags_pulse_port.c
+++ b/ags/audio/pulse/ags_pulse_port.c
@@ -19,18 +19,7 @@
 
 #include <ags/audio/pulse/ags_pulse_port.h>
 
-#include <ags/util/ags_id_generator.h>
-
-#include <ags/object/ags_application_context.h>
-#include <ags/object/ags_distributed_manager.h>
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_distributed_manager.h>
-#include <ags/object/ags_soundcard.h>
-#include <ags/object/ags_sequencer.h>
-
-#include <ags/thread/ags_mutex_manager.h>
-#include <ags/thread/ags_task_thread.h>
-#include <ags/thread/ags_polling_thread.h>
+#include <ags/libags.h>
 
 #include <ags/audio/ags_sound_provider.h>
 #include <ags/audio/ags_audio_signal.h>
diff --git a/ags/audio/recall/ags_capture_sound_audio.c b/ags/audio/recall/ags_capture_sound_audio.c
new file mode 100644
index 0000000..6be377f
--- /dev/null
+++ b/ags/audio/recall/ags_capture_sound_audio.c
@@ -0,0 +1,781 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2018 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/recall/ags_capture_sound_audio.h>
+
+#include <ags/object/ags_plugin.h>
+
+#include <ags/i18n.h>
+
+void ags_capture_sound_audio_class_init(AgsCaptureSoundAudioClass *capture_sound_audio);
+void ags_capture_sound_audio_plugin_interface_init(AgsPluginInterface *plugin);
+void ags_capture_sound_audio_init(AgsCaptureSoundAudio *capture_sound_audio);
+void ags_capture_sound_audio_set_property(GObject *gobject,
+					  guint prop_id,
+					  const GValue *value,
+					  GParamSpec *param_spec);
+void ags_capture_sound_audio_get_property(GObject *gobject,
+					  guint prop_id,
+					  GValue *value,
+					  GParamSpec *param_spec);
+void ags_capture_sound_audio_finalize(GObject *gobject);
+void ags_capture_sound_audio_set_ports(AgsPlugin *plugin, GList *port);
+
+/**
+ * SECTION:ags_capture_sound_audio
+ * @short_description: capture audio sound
+ * @title: AgsCaptureSoundAudio
+ * @section_id:
+ * @include: ags/audio/recall/ags_capture_sound_audio.h
+ *
+ * The #AgsCaptureSoundAudio class provides ports to the effect processor.
+ */
+
+enum{
+  PROP_0,
+  PROP_PLAYBACK,
+  PROP_RECORD,
+  PROP_FILENAME,
+  PROP_AUDIO_CHANNELS,
+  PROP_FORMAT,
+  PROP_SAMPLERATE,
+  PROP_BUFFER_SIZE,
+};
+
+static gpointer ags_capture_sound_audio_parent_class = NULL;
+static AgsPluginInterface *ags_capture_sound_parent_plugin_interface;
+
+static const gchar *ags_capture_sound_audio_plugin_name = "ags-capture-sound";
+static const gchar *ags_capture_sound_audio_specifier[] = {
+  "./playback[0]"
+  "./record[0]",
+  "./filename[0]",
+  "./audio-channels[0]",
+  "./format[0]",
+  "./samplerate[0]",
+  "./buffer-size[0]",
+};
+
+static const gchar *ags_capture_sound_audio_control_port[] = {
+  "1/7",
+  "2/7",
+  "3/7",
+  "4/7",
+  "5/7",
+  "6/7",
+  "7/7",
+};
+
+GType
+ags_capture_sound_audio_get_type()
+{
+  static GType ags_type_capture_sound_audio = 0;
+
+  if(!ags_type_capture_sound_audio){
+    static const GTypeInfo ags_capture_sound_audio_info = {
+      sizeof (AgsCaptureSoundAudioClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      (GClassInitFunc) ags_capture_sound_audio_class_init,
+      NULL, /* class_finalize */
+      NULL, /* class_audio */
+      sizeof (AgsCaptureSoundAudio),
+      0,    /* n_preallocs */
+      (GInstanceInitFunc) ags_capture_sound_audio_init,
+    };
+
+    static const GInterfaceInfo ags_plugin_interface_info = {
+      (GInterfaceInitFunc) ags_capture_sound_audio_plugin_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };    
+
+    ags_type_capture_sound_audio = g_type_register_static(AGS_TYPE_RECALL_AUDIO,
+							  "AgsCaptureSoundAudio",
+							  &ags_capture_sound_audio_info,
+							  0);
+
+    g_type_add_interface_static(ags_type_capture_sound_audio,
+				AGS_TYPE_PLUGIN,
+				&ags_plugin_interface_info);
+  }
+
+  return(ags_type_capture_sound_audio);
+}
+
+void
+ags_capture_sound_audio_class_init(AgsCaptureSoundAudioClass *capture_sound_audio)
+{
+  GObjectClass *gobject;
+
+  GParamSpec *param_spec;
+
+  ags_capture_sound_audio_parent_class = g_type_class_peek_parent(capture_sound_audio);
+
+  /* GObjectClass */
+  gobject = (GObjectClass *) capture_sound_audio;
+
+  gobject->set_property = ags_capture_sound_audio_set_property;
+  gobject->get_property = ags_capture_sound_audio_get_property;
+
+  gobject->finalize = ags_capture_sound_audio_finalize;
+
+  /* properties */
+  /**
+   * AgsCaptureSoundAudio:playback:
+   * 
+   * The playback port.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_object("playback",
+				   i18n_pspec("if do playback"),
+				   i18n_pspec("If playback should be performed"),
+				   AGS_TYPE_PORT,
+				   G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_PLAYBACK,
+				  param_spec);
+
+  /**
+   * AgsCaptureSoundAudio:record:
+   * 
+   * The record port.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_object("record",
+				   i18n_pspec("if do record"),
+				   i18n_pspec("If record data for later use should be done"),
+				   AGS_TYPE_PORT,
+				   G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_RECORD,
+				  param_spec);
+
+  /**
+   * AgsCaptureSoundAudio:filename:
+   * 
+   * The filename port.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_object("filename",
+				   i18n_pspec("filename of record"),
+				   i18n_pspec("The filename of record"),
+				   AGS_TYPE_PORT,
+				   G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_FILENAME,
+				  param_spec);
+
+  /**
+   * AgsCaptureSoundAudio:audio-channels:
+   * 
+   * The audio channels port.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_object("audio-channels",
+				   i18n_pspec("audio channels"),
+				   i18n_pspec("Audio channels count of file"),
+				   AGS_TYPE_PORT,
+				   G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_AUDIO_CHANNELS,
+				  param_spec);
+
+  /**
+   * AgsCaptureSoundAudio:format:
+   * 
+   * The format port.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_object("format",
+				   i18n_pspec("format"),
+				   i18n_pspec("Format to use of file"),
+				   AGS_TYPE_PORT,
+				   G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_FORMAT,
+				  param_spec);
+
+  /**
+   * AgsCaptureSoundAudio:samplerate:
+   * 
+   * The samplerate port.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_object("samplerate",
+				   i18n_pspec("samplerate"),
+				   i18n_pspec("Samplerate to use of file"),
+				   AGS_TYPE_PORT,
+				   G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_SAMPLERATE,
+				  param_spec);
+
+  /**
+   * AgsCaptureSoundAudio:buffer-size:
+   * 
+   * The buffer size port.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_object("buffer-size",
+				   i18n_pspec("buffer size"),
+				   i18n_pspec("Buffer size to use"),
+				   AGS_TYPE_PORT,
+				   G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_BUFFER_SIZE,
+				  param_spec);
+}
+
+void
+ags_capture_sound_audio_plugin_interface_init(AgsPluginInterface *plugin)
+{
+  ags_capture_sound_parent_plugin_interface = g_type_interface_peek_parent(plugin);
+
+  plugin->set_ports = ags_capture_sound_audio_set_ports;
+}
+
+void
+ags_capture_sound_audio_init(AgsCaptureSoundAudio *capture_sound_audio)
+{
+  GList *port;
+
+  AGS_RECALL(capture_sound_audio)->name = "ags-capture-sound";
+  AGS_RECALL(capture_sound_audio)->version = AGS_RECALL_DEFAULT_VERSION;
+  AGS_RECALL(capture_sound_audio)->build_id = AGS_RECALL_DEFAULT_BUILD_ID;
+  AGS_RECALL(capture_sound_audio)->xml_type = "ags-capture-sound-audio";
+
+  port = NULL;
+
+  /* playback */
+  capture_sound_audio->playback = g_object_new(AGS_TYPE_PORT,
+					       "plugin-name", ags_capture_sound_audio_plugin_name,
+					       "specifier", ags_capture_sound_audio_specifier[0],
+					       "control-port", ags_capture_sound_audio_control_port[0],
+					       "port-value-is-pointer", FALSE,
+					       "port-value-type", G_TYPE_BOOLEAN,
+					       NULL);
+  g_object_ref(capture_sound_audio->playback);
+  
+  capture_sound_audio->playback->port_value.ags_port_boolean = TRUE;
+
+  /* add to port */
+  port = g_list_prepend(port, capture_sound_audio->playback);
+  g_object_ref(capture_sound_audio->playback);
+  
+  /* record */
+  capture_sound_audio->record = g_object_new(AGS_TYPE_PORT,
+					     "plugin-name", ags_capture_sound_audio_plugin_name,
+					     "specifier", ags_capture_sound_audio_specifier[1],
+					     "control-port", ags_capture_sound_audio_control_port[1],
+					     "port-value-is-pointer", FALSE,
+					     "port-value-type", G_TYPE_BOOLEAN,
+					     NULL);
+  g_object_ref(capture_sound_audio->record);
+  
+  capture_sound_audio->record->port_value.ags_port_boolean = FALSE;
+
+  /* add to port */
+  port = g_list_prepend(port, capture_sound_audio->record);
+  g_object_ref(capture_sound_audio->record);
+
+  /* filename */
+  capture_sound_audio->filename = g_object_new(AGS_TYPE_PORT,
+					       "plugin-name", ags_capture_sound_audio_plugin_name,
+					       "specifier", ags_capture_sound_audio_specifier[2],
+					       "control-port", ags_capture_sound_audio_control_port[2],
+					       "port-value-is-pointer", FALSE,
+					       "port-value-type", G_TYPE_POINTER,
+					       NULL);
+  g_object_ref(capture_sound_audio->filename);
+
+  capture_sound_audio->filename->port_value.ags_port_pointer = NULL;
+
+  /* add to port */
+  port = g_list_prepend(port, capture_sound_audio->filename);
+  g_object_ref(capture_sound_audio->filename);
+
+  /* audio channels */
+  capture_sound_audio->audio_channels = g_object_new(AGS_TYPE_PORT,
+					     "plugin-name", ags_capture_sound_audio_plugin_name,
+					     "specifier", ags_capture_sound_audio_specifier[3],
+					     "control-port", ags_capture_sound_audio_control_port[3],
+					     "port-value-is-pointer", FALSE,
+					     "port-value-type", G_TYPE_UINT,
+					     NULL);
+  g_object_ref(capture_sound_audio->audio_channels);
+  
+  capture_sound_audio->audio_channels->port_value.ags_port_uint = AGS_SOUNDCARD_DEFAULT_PCM_CHANNELS;
+
+  /* add to port */
+  port = g_list_prepend(port, capture_sound_audio->audio_channels);
+  g_object_ref(capture_sound_audio->audio_channels);
+
+  /* format */
+  capture_sound_audio->format = g_object_new(AGS_TYPE_PORT,
+					     "plugin-name", ags_capture_sound_audio_plugin_name,
+					     "specifier", ags_capture_sound_audio_specifier[4],
+					     "control-port", ags_capture_sound_audio_control_port[4],
+					     "port-value-is-pointer", FALSE,
+					     "port-value-type", G_TYPE_UINT,
+					     NULL);
+  g_object_ref(capture_sound_audio->format);
+  
+  capture_sound_audio->format->port_value.ags_port_uint = AGS_SOUNDCARD_DEFAULT_FORMAT;
+
+  /* add to port */
+  port = g_list_prepend(port, capture_sound_audio->format);
+  g_object_ref(capture_sound_audio->format);
+
+  /* samplerate */
+  capture_sound_audio->samplerate = g_object_new(AGS_TYPE_PORT,
+					     "plugin-name", ags_capture_sound_audio_plugin_name,
+					     "specifier", ags_capture_sound_audio_specifier[5],
+					     "control-port", ags_capture_sound_audio_control_port[5],
+					     "port-value-is-pointer", FALSE,
+					     "port-value-type", G_TYPE_UINT,
+					     NULL);
+  g_object_ref(capture_sound_audio->samplerate);
+  
+  capture_sound_audio->samplerate->port_value.ags_port_uint = AGS_SOUNDCARD_DEFAULT_SAMPLERATE;
+
+  /* add to port */
+  port = g_list_prepend(port, capture_sound_audio->samplerate);
+  g_object_ref(capture_sound_audio->samplerate);
+
+  /* buffer size */
+  capture_sound_audio->buffer_size = g_object_new(AGS_TYPE_PORT,
+					     "plugin-name", ags_capture_sound_audio_plugin_name,
+					     "specifier", ags_capture_sound_audio_specifier[6],
+					     "control-port", ags_capture_sound_audio_control_port[6],
+					     "port-value-is-pointer", FALSE,
+					     "port-value-type", G_TYPE_UINT,
+					     NULL);
+  g_object_ref(capture_sound_audio->buffer_size);
+  
+  capture_sound_audio->buffer_size->port_value.ags_port_uint = AGS_SOUNDCARD_DEFAULT_BUFFER_SIZE;
+
+  /* add to port */
+  port = g_list_prepend(port, capture_sound_audio->buffer_size);
+  g_object_ref(capture_sound_audio->buffer_size);
+
+  /* set port */
+  AGS_RECALL(capture_sound_audio)->port = port;
+}
+
+void
+ags_capture_sound_audio_set_property(GObject *gobject,
+				     guint prop_id,
+				     const GValue *value,
+				     GParamSpec *param_spec)
+{
+  AgsCaptureSoundAudio *capture_sound_audio;
+
+  capture_sound_audio = AGS_CAPTURE_SOUND_AUDIO(gobject);
+
+  switch(prop_id){
+  case PROP_PLAYBACK:
+    {
+      AgsPort *playback;
+
+      playback = (AgsPort *) g_value_get_object(value);
+
+      if(capture_sound_audio->playback == playback){
+	return;
+      }
+
+      if(capture_sound_audio->playback != NULL){
+	g_object_unref(G_OBJECT(capture_sound_audio->playback));
+      }
+      
+      if(playback != NULL){
+	g_object_ref(G_OBJECT(playback));
+      }
+      
+      capture_sound_audio->playback = playback;
+    }
+    break;
+  case PROP_RECORD:
+    {
+      AgsPort *record;
+
+      record = (AgsPort *) g_value_get_object(value);
+
+      if(capture_sound_audio->record == record){
+	return;
+      }
+
+      if(capture_sound_audio->record != NULL){
+	g_object_unref(G_OBJECT(capture_sound_audio->record));
+      }
+      
+      if(record != NULL){
+	g_object_ref(G_OBJECT(record));
+      }
+      
+      capture_sound_audio->record = record;
+    }
+    break;
+  case PROP_FILENAME:
+    {
+      AgsPort *filename;
+
+      filename = (AgsPort *) g_value_get_object(value);
+
+      if(capture_sound_audio->filename == filename){
+	return;
+      }
+
+      if(capture_sound_audio->filename != NULL){
+	g_object_unref(G_OBJECT(capture_sound_audio->filename));
+      }
+      
+      if(filename != NULL){
+	g_object_ref(G_OBJECT(filename));
+      }
+      
+      capture_sound_audio->filename = filename;
+    }
+    break;
+  case PROP_AUDIO_CHANNELS:
+    {
+      AgsPort *audio_channels;
+
+      audio_channels = (AgsPort *) g_value_get_object(value);
+
+      if(capture_sound_audio->audio_channels == audio_channels){
+	return;
+      }
+
+      if(capture_sound_audio->audio_channels != NULL){
+	g_object_unref(G_OBJECT(capture_sound_audio->audio_channels));
+      }
+      
+      if(audio_channels != NULL){
+	g_object_ref(G_OBJECT(audio_channels));
+      }
+      
+      capture_sound_audio->audio_channels = audio_channels;
+    }
+    break;
+  case PROP_FORMAT:
+    {
+      AgsPort *format;
+
+      format = (AgsPort *) g_value_get_object(value);
+
+      if(capture_sound_audio->format == format){
+	return;
+      }
+
+      if(capture_sound_audio->format != NULL){
+	g_object_unref(G_OBJECT(capture_sound_audio->format));
+      }
+      
+      if(format != NULL){
+	g_object_ref(G_OBJECT(format));
+      }
+      
+      capture_sound_audio->format = format;
+    }
+    break;
+  case PROP_SAMPLERATE:
+    {
+      AgsPort *samplerate;
+
+      samplerate = (AgsPort *) g_value_get_object(value);
+
+      if(capture_sound_audio->samplerate == samplerate){
+	return;
+      }
+
+      if(capture_sound_audio->samplerate != NULL){
+	g_object_unref(G_OBJECT(capture_sound_audio->samplerate));
+      }
+      
+      if(samplerate != NULL){
+	g_object_ref(G_OBJECT(samplerate));
+      }
+      
+      capture_sound_audio->samplerate = samplerate;
+    }
+    break;
+  case PROP_BUFFER_SIZE:
+    {
+      AgsPort *buffer_size;
+
+      buffer_size = (AgsPort *) g_value_get_object(value);
+
+      if(capture_sound_audio->buffer_size == buffer_size){
+	return;
+      }
+
+      if(capture_sound_audio->buffer_size != NULL){
+	g_object_unref(G_OBJECT(capture_sound_audio->buffer_size));
+      }
+      
+      if(buffer_size != NULL){
+	g_object_ref(G_OBJECT(buffer_size));
+      }
+      
+      capture_sound_audio->buffer_size = buffer_size;
+    }
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
+    break;
+  }  
+}
+
+void
+ags_capture_sound_audio_get_property(GObject *gobject,
+				     guint prop_id,
+				     GValue *value,
+				     GParamSpec *param_spec)
+{
+  AgsCaptureSoundAudio *capture_sound_audio;
+
+  capture_sound_audio = AGS_CAPTURE_SOUND_AUDIO(gobject);
+
+  switch(prop_id){
+  case PROP_PLAYBACK:
+    {
+      g_value_set_object(value, capture_sound_audio->playback);
+    }
+    break;
+  case PROP_RECORD:
+    {
+      g_value_set_object(value, capture_sound_audio->record);
+    }
+    break;
+  case PROP_FILENAME:
+    {
+      g_value_set_object(value, capture_sound_audio->filename);
+    }
+    break;
+  case PROP_AUDIO_CHANNELS:
+    {
+      g_value_set_object(value, capture_sound_audio->audio_channels);
+    }
+    break;
+  case PROP_FORMAT:
+    {
+      g_value_set_object(value, capture_sound_audio->format);
+    }
+    break;
+  case PROP_SAMPLERATE:
+    {
+      g_value_set_object(value, capture_sound_audio->samplerate);
+    }
+    break;
+  case PROP_BUFFER_SIZE:
+    {
+      g_value_set_object(value, capture_sound_audio->buffer_size);
+    }
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
+    break;
+  }
+}
+
+void
+ags_capture_sound_audio_dispose(GObject *gobject)
+{
+  AgsCaptureSoundAudio *capture_sound_audio;
+
+  capture_sound_audio = AGS_CAPTURE_SOUND_AUDIO(gobject);
+
+  /* playback */
+  if(capture_sound_audio->playback != NULL){
+    g_object_unref(capture_sound_audio->playback);
+
+    capture_sound_audio->playback = NULL;
+  }
+
+  /* record */
+  if(capture_sound_audio->record != NULL){
+    g_object_unref(capture_sound_audio->record);
+
+    capture_sound_audio->record = NULL;
+  }
+
+  /* filename */
+  if(capture_sound_audio->filename != NULL){
+    g_object_unref(capture_sound_audio->filename);
+
+    capture_sound_audio->filename = NULL;
+  }
+
+  /* audio channels */
+  if(capture_sound_audio->audio_channels != NULL){
+    g_object_unref(capture_sound_audio->audio_channels);
+
+    capture_sound_audio->audio_channels = NULL;
+  }
+
+  /* format */
+  if(capture_sound_audio->format != NULL){
+    g_object_unref(capture_sound_audio->format);
+
+    capture_sound_audio->format = NULL;
+  }
+
+  /* samplerate */
+  if(capture_sound_audio->samplerate != NULL){
+    g_object_unref(capture_sound_audio->samplerate);
+
+    capture_sound_audio->samplerate = NULL;
+  }
+
+  /* buffer size */
+  if(capture_sound_audio->buffer_size != NULL){
+    g_object_unref(capture_sound_audio->buffer_size);
+
+    capture_sound_audio->buffer_size = NULL;
+  }
+
+  /* call parent */
+  G_OBJECT_CLASS(ags_capture_sound_audio_parent_class)->dispose(gobject);
+}
+
+void
+ags_capture_sound_audio_finalize(GObject *gobject)
+{
+  AgsCaptureSoundAudio *capture_sound_audio;
+
+  capture_sound_audio = AGS_CAPTURE_SOUND_AUDIO(gobject);
+
+  /* playback */
+  if(capture_sound_audio->playback != NULL){
+    g_object_unref(capture_sound_audio->playback);
+  }
+
+  /* record */
+  if(capture_sound_audio->record != NULL){
+    g_object_unref(capture_sound_audio->record);
+  }
+
+  /* filename */
+  if(capture_sound_audio->filename != NULL){
+    g_object_unref(capture_sound_audio->filename);
+  }
+
+  /* audio channels */
+  if(capture_sound_audio->audio_channels != NULL){
+    g_object_unref(capture_sound_audio->audio_channels);
+  }
+
+  /* format */
+  if(capture_sound_audio->format != NULL){
+    g_object_unref(capture_sound_audio->format);
+  }
+
+  /* samplerate */
+  if(capture_sound_audio->samplerate != NULL){
+    g_object_unref(capture_sound_audio->samplerate);
+  }
+
+  /* buffer size */
+  if(capture_sound_audio->buffer_size != NULL){
+    g_object_unref(capture_sound_audio->buffer_size);
+  }
+
+  /* call parent */
+  G_OBJECT_CLASS(ags_capture_sound_audio_parent_class)->finalize(gobject);
+}
+
+void
+ags_capture_sound_audio_set_ports(AgsPlugin *plugin, GList *port)
+{
+  while(port != NULL){
+    if(!strncmp(AGS_PORT(port->data)->specifier,
+		"./playback[0]",
+		11)){
+      g_object_set(G_OBJECT(plugin),
+		   "playback", AGS_PORT(port->data),
+		   NULL);
+    }else if(!strncmp(AGS_PORT(port->data)->specifier,
+		      "./record[0]",
+		      11)){
+      g_object_set(G_OBJECT(plugin),
+		   "record", AGS_PORT(port->data),
+		   NULL);
+    }else if(!strncmp(AGS_PORT(port->data)->specifier,
+		      "./filename[0]",
+		      11)){
+      g_object_set(G_OBJECT(plugin),
+		   "filename", AGS_PORT(port->data),
+		   NULL);
+    }else if(!strncmp(AGS_PORT(port->data)->specifier,
+		      "./audio-channels[0]",
+		      11)){
+      g_object_set(G_OBJECT(plugin),
+		   "audio-channels", AGS_PORT(port->data),
+		   NULL);
+    }else if(!strncmp(AGS_PORT(port->data)->specifier,
+		      "./format[0]",
+		      11)){
+      g_object_set(G_OBJECT(plugin),
+		   "format", AGS_PORT(port->data),
+		   NULL);
+    }else if(!strncmp(AGS_PORT(port->data)->specifier,
+		      "./samplerate[0]",
+		      11)){
+      g_object_set(G_OBJECT(plugin),
+		   "samplerate", AGS_PORT(port->data),
+		   NULL);
+    }else if(!strncmp(AGS_PORT(port->data)->specifier,
+		      "./buffer-size[0]",
+		      11)){
+      g_object_set(G_OBJECT(plugin),
+		   "buffer-size", AGS_PORT(port->data),
+		   NULL);
+    }
+
+    port = port->next;
+  }
+}
+
+/**
+ * ags_capture_sound_audio_new:
+ *
+ * Creates an #AgsCaptureSoundAudio
+ *
+ * Returns: a new #AgsCaptureSoundAudio
+ *
+ * Since: 1.4.0
+ */
+AgsCaptureSoundAudio*
+ags_capture_sound_audio_new()
+{
+  AgsCaptureSoundAudio *capture_sound_audio;
+
+  capture_sound_audio = (AgsCaptureSoundAudio *) g_object_new(AGS_TYPE_CAPTURE_SOUND_AUDIO,
+							      NULL);
+
+  return(capture_sound_audio);
+}
diff --git a/ags/audio/recall/ags_capture_sound_audio.h b/ags/audio/recall/ags_capture_sound_audio.h
new file mode 100644
index 0000000..c27c744
--- /dev/null
+++ b/ags/audio/recall/ags_capture_sound_audio.h
@@ -0,0 +1,62 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2018 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_CAPTURE_SOUND_AUDIO_H__
+#define __AGS_CAPTURE_SOUND_AUDIO_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <ags/audio/ags_recall_audio.h>
+
+#define AGS_TYPE_CAPTURE_SOUND_AUDIO                (ags_capture_sound_audio_get_type())
+#define AGS_CAPTURE_SOUND_AUDIO(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_CAPTURE_SOUND_AUDIO, AgsCaptureSoundAudio))
+#define AGS_CAPTURE_SOUND_AUDIO_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_CAPTURE_SOUND_AUDIO, AgsCaptureSoundAudio))
+#define AGS_IS_CAPTURE_SOUND_AUDIO(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AGS_TYPE_CAPTURE_SOUND_AUDIO))
+#define AGS_IS_CAPTURE_SOUND_AUDIO_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_CAPTURE_SOUND_AUDIO))
+#define AGS_CAPTURE_SOUND_AUDIO_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), AGS_TYPE_CAPTURE_SOUND_AUDIO, AgsCaptureSoundAudioClass))
+
+typedef struct _AgsCaptureSoundAudio AgsCaptureSoundAudio;
+typedef struct _AgsCaptureSoundAudioClass AgsCaptureSoundAudioClass;
+
+struct _AgsCaptureSoundAudio
+{
+  AgsRecallAudio recall_audio;
+
+  AgsPort *playback;
+
+  AgsPort *record;
+  AgsPort *filename;
+
+  AgsPort *audio_channels;
+  AgsPort *format;
+  AgsPort *samplerate;
+  AgsPort *buffer_size;
+};
+
+struct _AgsCaptureSoundAudioClass
+{
+  AgsRecallAudioClass recall_audio;
+};
+
+GType ags_capture_sound_audio_get_type();
+
+AgsCaptureSoundAudio* ags_capture_sound_audio_new();
+
+#endif /*__AGS_CAPTURE_SOUND_AUDIO_H__*/
diff --git a/ags/audio/recall/ags_capture_sound_audio_run.c b/ags/audio/recall/ags_capture_sound_audio_run.c
new file mode 100644
index 0000000..9da771e
--- /dev/null
+++ b/ags/audio/recall/ags_capture_sound_audio_run.c
@@ -0,0 +1,324 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2017 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/recall/ags_capture_sound_audio_run.h>
+#include <ags/audio/recall/ags_capture_sound_audio.h>
+
+#include <ags/libags.h>
+
+#include <ags/audio/ags_recall_id.h>
+#include <ags/audio/ags_recall_container.h>
+
+#include <ags/audio/thread/ags_audio_loop.h>
+#include <ags/audio/thread/ags_soundcard_thread.h>
+
+#include <ags/i18n.h>
+
+void ags_capture_sound_audio_run_class_init(AgsCaptureSoundAudioRunClass *capture_sound_audio_run);
+void ags_capture_sound_audio_run_connectable_interface_init(AgsConnectableInterface *connectable);
+void ags_capture_sound_audio_run_dynamic_connectable_interface_init(AgsDynamicConnectableInterface *dynamic_connectable);
+void ags_capture_sound_audio_run_plugin_interface_init(AgsPluginInterface *plugin);
+void ags_capture_sound_audio_run_init(AgsCaptureSoundAudioRun *capture_sound_audio_run);
+void ags_capture_sound_audio_run_dispose(GObject *gobject);
+void ags_capture_sound_audio_run_finalize(GObject *gobject);
+void ags_capture_sound_audio_run_connect(AgsConnectable *connectable);
+void ags_capture_sound_audio_run_disconnect(AgsConnectable *connectable);
+void ags_capture_sound_audio_run_connect_dynamic(AgsDynamicConnectable *dynamic_connectable);
+void ags_capture_sound_audio_run_disconnect_dynamic(AgsDynamicConnectable *dynamic_connectable); 
+void ags_capture_sound_audio_run_read(AgsFile *file, xmlNode *node, AgsPlugin *plugin);
+xmlNode* ags_capture_sound_audio_run_write(AgsFile *file, xmlNode *parent, AgsPlugin *plugin);
+
+AgsRecall* ags_capture_sound_audio_run_duplicate(AgsRecall *recall,
+						 AgsRecallID *recall_id,
+						 guint *n_params, GParameter *parameter);
+void ags_capture_sound_audio_run_run_init_pre(AgsRecall *recall);
+void ags_capture_sound_audio_run_run_pre(AgsRecall *recall);
+
+/**
+ * SECTION:ags_capture_sound_audio_run
+ * @short_description: capture sound
+ * @title: AgsCaptureSoundAudioRun
+ * @section_id:
+ * @include: ags/audio/recall/ags_capture_sound_audio_run.h
+ *
+ * The #AgsCaptureSoundAudioRun does capture sound.
+ */
+
+static gpointer ags_capture_sound_audio_run_parent_class = NULL;
+static AgsConnectableInterface* ags_capture_sound_audio_run_parent_connectable_interface;
+static AgsDynamicConnectableInterface *ags_capture_sound_audio_run_parent_dynamic_connectable_interface;
+static AgsPluginInterface *ags_capture_sound_audio_run_parent_plugin_interface;
+
+GType
+ags_capture_sound_audio_run_get_type()
+{
+  static GType ags_type_capture_sound_audio_run = 0;
+
+  if(!ags_type_capture_sound_audio_run){
+    static const GTypeInfo ags_capture_sound_audio_run_info = {
+      sizeof (AgsCaptureSoundAudioRunClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      (GClassInitFunc) ags_capture_sound_audio_run_class_init,
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof (AgsCaptureSoundAudioRun),
+      0,    /* n_preallocs */
+      (GInstanceInitFunc) ags_capture_sound_audio_run_init,
+    };
+
+    static const GInterfaceInfo ags_connectable_interface_info = {
+      (GInterfaceInitFunc) ags_capture_sound_audio_run_connectable_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };
+
+    static const GInterfaceInfo ags_dynamic_connectable_interface_info = {
+      (GInterfaceInitFunc) ags_capture_sound_audio_run_dynamic_connectable_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };
+
+    static const GInterfaceInfo ags_plugin_interface_info = {
+      (GInterfaceInitFunc) ags_capture_sound_audio_run_plugin_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };
+
+    ags_type_capture_sound_audio_run = g_type_register_static(AGS_TYPE_RECALL_AUDIO_RUN,
+							      "AgsCaptureSoundAudioRun",
+							      &ags_capture_sound_audio_run_info,
+							      0);
+
+    g_type_add_interface_static(ags_type_capture_sound_audio_run,
+				AGS_TYPE_CONNECTABLE,
+				&ags_connectable_interface_info);
+
+    g_type_add_interface_static(ags_type_capture_sound_audio_run,
+				AGS_TYPE_DYNAMIC_CONNECTABLE,
+				&ags_dynamic_connectable_interface_info);
+
+    g_type_add_interface_static(ags_type_capture_sound_audio_run,
+				AGS_TYPE_PLUGIN,
+				&ags_plugin_interface_info);
+  }
+
+  return (ags_type_capture_sound_audio_run);
+}
+
+void
+ags_capture_sound_audio_run_class_init(AgsCaptureSoundAudioRunClass *capture_sound_audio_run)
+{
+  GObjectClass *gobject;
+  AgsRecallClass *recall;
+
+  ags_capture_sound_audio_run_parent_class = g_type_class_peek_parent(capture_sound_audio_run);
+
+  /* GObjectClass */
+  gobject = (GObjectClass *) capture_sound_audio_run;
+
+  gobject->dispose = ags_capture_sound_audio_run_dispose;
+  gobject->finalize = ags_capture_sound_audio_run_finalize;
+
+  /* AgsRecallClass */
+  recall = (AgsRecallClass *) capture_sound_audio_run;
+
+  recall->duplicate = ags_capture_sound_audio_run_duplicate;
+  recall->run_init_pre = ags_capture_sound_audio_run_run_init_pre;
+  recall->run_pre = ags_capture_sound_audio_run_run_pre;
+}
+
+void
+ags_capture_sound_audio_run_connectable_interface_init(AgsConnectableInterface *connectable)
+{
+  ags_capture_sound_audio_run_parent_connectable_interface = g_type_interface_peek_parent(connectable);
+
+  connectable->connect = ags_capture_sound_audio_run_connect;
+  connectable->disconnect = ags_capture_sound_audio_run_disconnect;
+}
+
+void
+ags_capture_sound_audio_run_dynamic_connectable_interface_init(AgsDynamicConnectableInterface *dynamic_connectable)
+{
+  ags_capture_sound_audio_run_parent_dynamic_connectable_interface = g_type_interface_peek_parent(dynamic_connectable);
+
+  dynamic_connectable->connect_dynamic = ags_capture_sound_audio_run_connect_dynamic;
+  dynamic_connectable->disconnect_dynamic = ags_capture_sound_audio_run_disconnect_dynamic;
+}
+
+void
+ags_capture_sound_audio_run_plugin_interface_init(AgsPluginInterface *plugin)
+{
+  ags_capture_sound_audio_run_parent_plugin_interface = g_type_interface_peek_parent(plugin);
+  
+  plugin->read = ags_capture_sound_audio_run_read;
+  plugin->write = ags_capture_sound_audio_run_write;
+}
+
+void
+ags_capture_sound_audio_run_init(AgsCaptureSoundAudioRun *capture_sound_audio_run)
+{
+  AGS_RECALL(capture_sound_audio_run)->name = "ags-capture-sound";
+  AGS_RECALL(capture_sound_audio_run)->version = AGS_RECALL_DEFAULT_VERSION;
+  AGS_RECALL(capture_sound_audio_run)->build_id = AGS_RECALL_DEFAULT_BUILD_ID;
+  AGS_RECALL(capture_sound_audio_run)->xml_type = "ags-capture-sound-audio-run";
+  AGS_RECALL(capture_sound_audio_run)->port = NULL;
+
+  capture_sound_audio_run->audio_file = NULL;
+}
+
+void
+ags_capture_sound_audio_run_dispose(GObject *gobject)
+{
+  AgsCaptureSoundAudioRun *capture_sound_audio_run;
+
+  capture_sound_audio_run = AGS_CAPTURE_SOUND_AUDIO_RUN(gobject);
+
+  /* call parent */
+  G_OBJECT_CLASS(ags_capture_sound_audio_run_parent_class)->dispose(gobject);
+}
+
+void
+ags_capture_sound_audio_run_finalize(GObject *gobject)
+{
+  AgsCaptureSoundAudioRun *capture_sound_audio_run;
+
+  capture_sound_audio_run = AGS_CAPTURE_SOUND_AUDIO_RUN(gobject);
+
+  /* call parent */
+  G_OBJECT_CLASS(ags_capture_sound_audio_run_parent_class)->finalize(gobject);
+}
+
+void
+ags_capture_sound_audio_run_connect(AgsConnectable *connectable)
+{
+  AgsCaptureSoundAudioRun *capture_sound_audio_run;
+
+  if((AGS_RECALL_CONNECTED & (AGS_RECALL(connectable)->flags)) != 0){
+    return;
+  }
+
+  /* call parent */
+  ags_capture_sound_audio_run_parent_connectable_interface->connect(connectable);
+
+  capture_sound_audio_run = AGS_CAPTURE_SOUND_AUDIO_RUN(connectable);
+}
+
+void
+ags_capture_sound_audio_run_disconnect(AgsConnectable *connectable)
+{
+  /* call parent */
+  ags_capture_sound_audio_run_parent_connectable_interface->disconnect(connectable);
+}
+
+void
+ags_capture_sound_audio_run_connect_dynamic(AgsDynamicConnectable *dynamic_connectable)
+{
+  AgsCaptureSoundAudioRun *capture_sound_audio_run;
+
+  if((AGS_RECALL_DYNAMIC_CONNECTED & (AGS_RECALL(dynamic_connectable)->flags)) != 0){
+    return;
+  }
+
+  capture_sound_audio_run = AGS_CAPTURE_SOUND_AUDIO_RUN(dynamic_connectable);
+
+  /* call parent */
+  ags_capture_sound_audio_run_parent_dynamic_connectable_interface->connect_dynamic(dynamic_connectable);  
+}
+
+void
+ags_capture_sound_audio_run_disconnect_dynamic(AgsDynamicConnectable *dynamic_connectable)
+{
+  AgsCaptureSoundAudioRun *capture_sound_audio_run;
+
+  /* call parent */
+  ags_capture_sound_audio_run_parent_dynamic_connectable_interface->disconnect_dynamic(dynamic_connectable);
+
+  capture_sound_audio_run = AGS_CAPTURE_SOUND_AUDIO_RUN(dynamic_connectable);
+}
+
+void
+ags_capture_sound_audio_run_read(AgsFile *file, xmlNode *node, AgsPlugin *plugin)
+{
+  /* read parent */
+  ags_capture_sound_audio_run_parent_plugin_interface->read(file, node, plugin);
+}
+
+xmlNode*
+ags_capture_sound_audio_run_write(AgsFile *file, xmlNode *parent, AgsPlugin *plugin)
+{
+  xmlNode *node;
+  
+  /* write parent */
+  node = ags_capture_sound_audio_run_parent_plugin_interface->write(file, parent, plugin);
+
+  return(node);
+}
+
+AgsRecall*
+ags_capture_sound_audio_run_duplicate(AgsRecall *recall,
+				      AgsRecallID *recall_id,
+				      guint *n_params, GParameter *parameter)
+{
+  AgsCaptureSoundAudioRun *copy;
+
+  copy = AGS_CAPTURE_SOUND_AUDIO_RUN(AGS_RECALL_CLASS(ags_capture_sound_audio_run_parent_class)->duplicate(recall,
+													   recall_id,
+													   n_params, parameter));
+
+  return((AgsRecall *) copy);
+}
+
+void
+ags_capture_sound_audio_run_run_init_pre(AgsRecall *recall)
+{
+  //TODO:JK: implement me
+
+  /* call parent */
+  AGS_RECALL_CLASS(ags_capture_sound_audio_run_parent_class)->run_init_pre(recall);
+}
+
+void
+ags_capture_sound_audio_run_run_pre(AgsRecall *recall)
+{
+  //TODO:JK: implement me
+  
+  /* call parent */
+  AGS_RECALL_CLASS(ags_capture_sound_audio_run_parent_class)->run_pre(recall);
+}
+
+/**
+ * ags_capture_sound_audio_run_new:
+ *
+ * Creates an #AgsCaptureSoundAudioRun
+ *
+ * Returns: a new #AgsCaptureSoundAudioRun
+ *
+ * Since: 1.4.0
+ */
+AgsCaptureSoundAudioRun*
+ags_capture_sound_audio_run_new()
+{
+  AgsCaptureSoundAudioRun *capture_sound_audio_run;
+
+  capture_sound_audio_run = (AgsCaptureSoundAudioRun *) g_object_new(AGS_TYPE_CAPTURE_SOUND_AUDIO_RUN,
+								     NULL);
+
+  return(capture_sound_audio_run);
+}
diff --git a/ags/audio/recall/ags_capture_sound_audio_run.h b/ags/audio/recall/ags_capture_sound_audio_run.h
new file mode 100644
index 0000000..4026990
--- /dev/null
+++ b/ags/audio/recall/ags_capture_sound_audio_run.h
@@ -0,0 +1,62 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2018 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_CAPTURE_SOUND_AUDIO_RUN_H__
+#define __AGS_CAPTURE_SOUND_AUDIO_RUN_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <ags/libags.h>
+
+#include <ags/audio/ags_recall.h>
+
+#include <ags/audio/ags_audio.h>
+
+#include <ags/audio/recall/ags_delay_audio_run.h>
+#include <ags/audio/recall/ags_count_beats_audio.h>
+#include <ags/audio/recall/ags_count_beats_audio_run.h>
+
+#define AGS_TYPE_CAPTURE_SOUND_AUDIO_RUN                (ags_capture_sound_audio_run_get_type())
+#define AGS_CAPTURE_SOUND_AUDIO_RUN(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_CAPTURE_SOUND_AUDIO_RUN, AgsCaptureSoundAudioRun))
+#define AGS_CAPTURE_SOUND_AUDIO_RUN_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_CAPTURE_SOUND_AUDIO_RUN, AgsCaptureSoundAudioRun))
+#define AGS_IS_CAPTURE_SOUND_AUDIO_RUN(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AGS_TYPE_CAPTURE_SOUND_AUDIO_RUN))
+#define AGS_IS_CAPTURE_SOUND_AUDIO_RUN_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_CAPTURE_SOUND_AUDIO_RUN))
+#define AGS_CAPTURE_SOUND_AUDIO_RUN_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), AGS_TYPE_CAPTURE_SOUND_AUDIO_RUN, AgsCaptureSoundAudioRunClass))
+
+typedef struct _AgsCaptureSoundAudioRun AgsCaptureSoundAudioRun;
+typedef struct _AgsCaptureSoundAudioRunClass AgsCaptureSoundAudioRunClass;
+
+struct _AgsCaptureSoundAudioRun
+{
+  AgsRecallAudioRun recall_audio_run;
+  
+  GObject *audio_file;
+};
+
+struct _AgsCaptureSoundAudioRunClass
+{
+  AgsRecallAudioRunClass recall_audio_run;
+};
+
+GType ags_capture_sound_audio_run_get_type();
+
+AgsCaptureSoundAudioRun* ags_capture_sound_audio_run_new();
+
+#endif /*__AGS_CAPTURE_SOUND_AUDIO_RUN_H__*/
diff --git a/ags/audio/recall/ags_copy_audio_signal.c b/ags/audio/recall/ags_copy_audio_signal.c
index 142985a..1f8b3fe 100644
--- a/ags/audio/recall/ags_copy_audio_signal.c
+++ b/ags/audio/recall/ags_copy_audio_signal.c
@@ -21,15 +21,12 @@
 #include <ags/audio/recall/ags_copy_channel.h>
 #include <ags/audio/recall/ags_copy_recycling.h>
 
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_dynamic_connectable.h>
-#include <ags/object/ags_soundcard.h>
+#include <ags/libags.h>
 
-#include <ags/thread/ags_mutex_manager.h>
-
-#include <ags/audio/ags_audio_signal.h>
-#include <ags/audio/ags_recycling.h>
 #include <ags/audio/ags_channel.h>
+#include <ags/audio/ags_input.h>
+#include <ags/audio/ags_recycling.h>
+#include <ags/audio/ags_audio_signal.h>
 #include <ags/audio/ags_recall_id.h>
 #include <ags/audio/ags_recall_channel.h>
 #include <ags/audio/ags_recall_channel_run.h>
@@ -334,6 +331,12 @@ ags_copy_audio_signal_run_inter(AgsRecall *recall)
 
   AGS_RECALL_CLASS(ags_copy_audio_signal_parent_class)->run_inter(recall);
 
+  if(recall->rt_safe &&
+     recall->recall_id->recycling_context->parent != NULL &&
+     AGS_RECALL_AUDIO_SIGNAL(recall)->source->note == NULL){
+    return;
+  }
+
   copy_audio_signal = AGS_COPY_AUDIO_SIGNAL(recall);
 
   source = AGS_RECALL_AUDIO_SIGNAL(copy_audio_signal)->source;
diff --git a/ags/audio/recall/ags_copy_channel_run.c b/ags/audio/recall/ags_copy_channel_run.c
index 2a12d8d..67a1606 100644
--- a/ags/audio/recall/ags_copy_channel_run.c
+++ b/ags/audio/recall/ags_copy_channel_run.c
@@ -20,9 +20,7 @@
 #include <ags/audio/recall/ags_copy_channel_run.h>
 #include <ags/audio/recall/ags_copy_recycling.h>
 
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_dynamic_connectable.h>
-#include <ags/object/ags_plugin.h>
+#include <ags/libags.h>
 
 #include <ags/audio/ags_audio.h>
 #include <ags/audio/ags_recall_id.h>
diff --git a/ags/audio/recall/ags_copy_pattern_channel_run.c b/ags/audio/recall/ags_copy_pattern_channel_run.c
index 701570b..156d53f 100644
--- a/ags/audio/recall/ags_copy_pattern_channel_run.c
+++ b/ags/audio/recall/ags_copy_pattern_channel_run.c
@@ -195,6 +195,8 @@ ags_copy_pattern_channel_run_init(AgsCopyPatternChannelRun *copy_pattern_channel
   AGS_RECALL(copy_pattern_channel_run)->port = NULL;
 
   AGS_RECALL(copy_pattern_channel_run)->child_type = G_TYPE_NONE;
+
+  copy_pattern_channel_run->note = NULL;
 }
 
 void
@@ -291,19 +293,87 @@ ags_copy_pattern_channel_run_resolve_dependencies(AgsRecall *recall)
 void
 ags_copy_pattern_channel_run_run_init_pre(AgsRecall *recall)
 {
-  AgsCopyPatternAudioRun *copy_pattern_audio_run;
+  AgsChannel *source;
+  AgsPattern *pattern;
+  AgsNote *note;
+  
+  AgsCopyPatternChannel *copy_pattern_channel;
   AgsCopyPatternChannelRun *copy_pattern_channel_run;
 
+  AgsMutexManager *mutex_manager;
+
+  guint pad;
+  guint i, i_stop;
+  
+  GValue pattern_value = { 0, };  
+
+  pthread_mutex_t *application_mutex;
+  pthread_mutex_t *source_mutex;  
+  pthread_mutex_t *pattern_mutex;
+  
+  mutex_manager = ags_mutex_manager_get_instance();
+  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
+
   AGS_RECALL_CLASS(ags_copy_pattern_channel_run_parent_class)->run_init_pre(recall);
 
+  /*  */
   copy_pattern_channel_run = AGS_COPY_PATTERN_CHANNEL_RUN(recall);
 
-  /* get AgsCopyPatternAudioRun */
-  copy_pattern_audio_run = AGS_COPY_PATTERN_AUDIO_RUN(AGS_RECALL_CHANNEL_RUN(copy_pattern_channel_run)->recall_audio_run);
+  /* get AgsCopyPatternChannel */
+  copy_pattern_channel = AGS_COPY_PATTERN_CHANNEL(copy_pattern_channel_run->recall_channel_run.recall_channel);
 
-  /* notify dependency */
-  ags_recall_notify_dependency(AGS_RECALL(copy_pattern_audio_run->count_beats_audio_run),
- 			       AGS_RECALL_NOTIFY_CHANNEL_RUN, 1);
+  /* 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);
+
+  /* get AgsPattern */
+  g_value_init(&pattern_value, G_TYPE_POINTER);
+  ags_port_safe_read(copy_pattern_channel->pattern,
+		     &pattern_value);
+
+  pattern = g_value_get_pointer(&pattern_value);
+
+  pthread_mutex_lock(application_mutex);
+  
+  pattern_mutex = ags_mutex_manager_lookup(mutex_manager,
+					   (GObject *) pattern);
+  
+  pthread_mutex_unlock(application_mutex);
+
+  /* add note */
+  pthread_mutex_lock(source_mutex);
+  
+  pad = source->pad;
+
+  pthread_mutex_unlock(source_mutex);
+
+  /* i stop */
+  pthread_mutex_lock(pattern_mutex);
+
+  i_stop = pattern->dim[2];
+
+  pthread_mutex_unlock(pattern_mutex);
+  
+  for(i = 0; i < i_stop; i++){
+    note = ags_note_new();
+
+    note->x[0] = i;
+    note->x[1] = i + 1;
+
+    note->y = pad;
+
+    copy_pattern_channel_run->note = g_list_prepend(copy_pattern_channel_run->note,
+						    note);
+    g_object_ref(note);
+  }
+
+  copy_pattern_channel_run->note = g_list_reverse(copy_pattern_channel_run->note);
 }
 
 void
@@ -321,6 +391,11 @@ ags_copy_pattern_channel_run_done(AgsRecall *recall)
   ags_recall_notify_dependency(AGS_RECALL(copy_pattern_audio_run->count_beats_audio_run),
  			       AGS_RECALL_NOTIFY_CHANNEL_RUN, -1);
 
+  g_list_free_full(copy_pattern_channel_run->note,
+		   g_object_unref);
+
+  copy_pattern_channel_run->note = NULL;
+  
   /* call parent */
   AGS_RECALL_CLASS(ags_copy_pattern_channel_run_parent_class)->done(recall);
 }
@@ -536,18 +611,12 @@ ags_copy_pattern_channel_run_sequencer_alloc_callback(AgsDelayAudioRun *delay_au
       
       while(recycling != end_recycling){
 	child_recall_id = AGS_RECALL(copy_pattern_channel_run)->recall_id;
-	
-	/* create audio signal */
-	audio_signal = ags_audio_signal_new(AGS_RECALL(copy_pattern_audio)->soundcard,
-					    (GObject *) recycling,
-					    (GObject *) child_recall_id);
-	ags_recycling_create_audio_signal_with_defaults(recycling,
-							audio_signal,
-							0.0, attack);
-	audio_signal->flags &= (~AGS_AUDIO_SIGNAL_TEMPLATE);
-	audio_signal->stream_current = audio_signal->stream_beginning;
 
 	/* apply preset */
+	note = g_list_nth(copy_pattern_channel_run->note,
+			  sequencer_counter)->data;	
+	note->rt_attack = attack;
+	
 	if(preset != NULL){
 	  AgsComplex *val;
 	  
@@ -555,16 +624,7 @@ ags_copy_pattern_channel_run_sequencer_alloc_callback(AgsDelayAudioRun *delay_au
 
 	  GError *error;
 	  
-	  note = ags_note_new();
-
 	  note->flags |= AGS_NOTE_ENVELOPE;
-
-	  note->x[0] = sequencer_counter;
-	  note->x[1] = sequencer_counter + 1;
-
-	  note->y = pad;
-
-	  audio_signal->note = note;
 	  
 	  /* get attack */
 	  g_value_init(&value,
@@ -643,8 +703,44 @@ ags_copy_pattern_channel_run_sequencer_alloc_callback(AgsDelayAudioRun *delay_au
 	  }
 	}
 	
-	ags_connectable_connect(AGS_CONNECTABLE(audio_signal));
-	
+	if(!AGS_RECALL(copy_pattern_audio)->rt_safe){
+	  /* create audio signal */
+	  audio_signal = ags_audio_signal_new(AGS_RECALL(copy_pattern_audio)->soundcard,
+					      (GObject *) recycling,
+					      (GObject *) child_recall_id);
+	  ags_recycling_create_audio_signal_with_defaults(recycling,
+							  audio_signal,
+							  0.0, attack);
+	  audio_signal->flags &= (~AGS_AUDIO_SIGNAL_TEMPLATE);
+	  audio_signal->stream_current = audio_signal->stream_beginning;
+
+	  ags_connectable_connect(AGS_CONNECTABLE(audio_signal));
+
+	  audio_signal->recall_id = (GObject *) child_recall_id;
+	  ags_recycling_add_audio_signal(recycling,
+					 audio_signal);
+
+	  g_object_set(audio_signal,
+		       "note", note,
+		       NULL);
+	}else{
+	  GList *list;
+
+	  audio_signal = NULL;
+	  list = ags_audio_signal_get_by_recall_id(recycling->audio_signal,
+						   child_recall_id);
+	    
+	  if(list != NULL){
+	    audio_signal = list->data;
+
+	    g_object_set(audio_signal,
+			 "note", note,
+			 NULL);
+	  }
+	    
+	  note->rt_offset = 0;
+	}
+		
 	/*
 	 * emit add_audio_signal on AgsRecycling
 	 */
@@ -652,10 +748,6 @@ ags_copy_pattern_channel_run_sequencer_alloc_callback(AgsDelayAudioRun *delay_au
 	g_message("play %x", AGS_RECALL(copy_pattern_channel_run)->recall_id);
 #endif
 
-	audio_signal->recall_id = (GObject *) child_recall_id;
-	ags_recycling_add_audio_signal(recycling,
-				       audio_signal);
-
 	/*
 	 * unref AgsAudioSignal because AgsCopyPatternChannelRun has no need for it
 	 * if you need a valid reference to audio_signal you have to g_object_ref(audio_signal)
diff --git a/ags/audio/recall/ags_copy_pattern_channel_run.h b/ags/audio/recall/ags_copy_pattern_channel_run.h
index 00b8c8a..0943f5f 100644
--- a/ags/audio/recall/ags_copy_pattern_channel_run.h
+++ b/ags/audio/recall/ags_copy_pattern_channel_run.h
@@ -40,6 +40,8 @@ struct _AgsCopyPatternChannelRun
   AgsRecallChannelRun recall_channel_run;
 
   gulong sequencer_alloc_handler;
+
+  GList *note;
 };
 
 struct _AgsCopyPatternChannelRunClass
diff --git a/ags/audio/recall/ags_count_beats_audio.c b/ags/audio/recall/ags_count_beats_audio.c
index 4acd49b..c845fff 100644
--- a/ags/audio/recall/ags_count_beats_audio.c
+++ b/ags/audio/recall/ags_count_beats_audio.c
@@ -20,10 +20,7 @@
 #include <ags/audio/recall/ags_count_beats_audio.h>
 #include <ags/audio/recall/ags_count_beats_audio_run.h>
 
-#include <ags/object/ags_soundcard.h>
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_tactable.h>
-#include <ags/object/ags_plugin.h>
+#include <ags/libags.h>
 
 #include <ags/i18n.h>
 
diff --git a/ags/audio/recall/ags_envelope_audio_signal.c b/ags/audio/recall/ags_envelope_audio_signal.c
index fac0065..4b5f788 100644
--- a/ags/audio/recall/ags_envelope_audio_signal.c
+++ b/ags/audio/recall/ags_envelope_audio_signal.c
@@ -20,11 +20,7 @@
 #include <ags/audio/recall/ags_envelope_audio_signal.h>
 #include <ags/audio/recall/ags_envelope_channel.h>
 
-#include <ags/lib/ags_complex.h>
-
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_dynamic_connectable.h>
-#include <ags/object/ags_soundcard.h>
+#include <ags/libags.h>
 
 #include <ags/audio/ags_channel.h>
 #include <ags/audio/ags_recycling.h>
@@ -49,7 +45,6 @@ void ags_envelope_audio_signal_connect_dynamic(AgsDynamicConnectable *dynamic_co
 void ags_envelope_audio_signal_disconnect_dynamic(AgsDynamicConnectable *dynamic_connectable);
 void ags_envelope_audio_signal_finalize(GObject *gobject);
 
-void ags_envelope_audio_signal_run_init_pre(AgsRecall *recall);
 void ags_envelope_audio_signal_run_inter(AgsRecall *recall);
 AgsRecall* ags_envelope_audio_signal_duplicate(AgsRecall *recall,
 					       AgsRecallID *recall_id,
@@ -132,7 +127,6 @@ ags_envelope_audio_signal_class_init(AgsEnvelopeAudioSignalClass *envelope_audio
   /* AgsRecallClass */
   recall = (AgsRecallClass *) envelope_audio_signal;
 
-  recall->run_init_pre = ags_envelope_audio_signal_run_init_pre;
   recall->run_inter = ags_envelope_audio_signal_run_inter;  
   recall->duplicate = ags_envelope_audio_signal_duplicate;
 }
@@ -237,78 +231,14 @@ ags_envelope_audio_signal_duplicate(AgsRecall *recall,
 }
 
 void
-ags_envelope_audio_signal_run_init_pre(AgsRecall *recall)
+ags_envelope_audio_signal_run_inter(AgsRecall *recall)
 {
   AgsEnvelopeChannel *envelope_channel;
   AgsEnvelopeAudioSignal *envelope_audio_signal;
 
   AgsAudioSignal *source;
-  AgsNote *note;
-
-  gdouble delay;
-  gdouble fixed_length;
-  guint buffer_size;
-  gboolean use_note_length, use_fixed_length;
-  
-  GValue value = {0,};
-  
-  /* call parent */
-  AGS_RECALL_CLASS(ags_envelope_audio_signal_parent_class)->run_init_pre(recall);
 
-  /*  */
-  envelope_channel = AGS_ENVELOPE_CHANNEL(AGS_RECALL_CHANNEL_RUN(recall->parent->parent)->recall_channel);
-  envelope_audio_signal = AGS_ENVELOPE_AUDIO_SIGNAL(recall);
-  
-  source = AGS_RECALL_AUDIO_SIGNAL(envelope_audio_signal)->source;
-  note = source->note;
-
-  delay = ags_soundcard_get_delay(AGS_SOUNDCARD(source->soundcard));
-  buffer_size = source->buffer_size;
-
-  /* get use note length port */
-  g_value_init(&value,
-	       G_TYPE_BOOLEAN);
-  ags_port_safe_read(envelope_channel->use_note_length,
-		     &value);
-  
-  use_note_length = g_value_get_boolean(&value);
-  g_value_unset(&value);
-
-  /* get use fixed length port */
-  g_value_init(&value,
-	       G_TYPE_BOOLEAN);
-  ags_port_safe_read(envelope_channel->use_fixed_length,
-		     &value);
-  
-  use_fixed_length = g_value_get_boolean(&value);
-  g_value_unset(&value);
-  
-  /* set frame count */
-  if(use_note_length){
-    envelope_audio_signal->frame_count = (note->x[1] - note->x[0]) * (delay * buffer_size);
-  }else if(use_fixed_length){
-    g_value_init(&value,
-		 G_TYPE_DOUBLE);
-
-    ags_port_safe_read(envelope_channel->fixed_length,
-		       &value);
-
-    fixed_length = g_value_get_double(&value);
-    g_value_unset(&value);
-
-    envelope_audio_signal->frame_count = fixed_length * (delay * buffer_size);
-  }else{
-    envelope_audio_signal->frame_count = AGS_RECALL_AUDIO_SIGNAL(recall)->source->frame_count;
-  }
-}
-
-void
-ags_envelope_audio_signal_run_inter(AgsRecall *recall)
-{
-  AgsEnvelopeAudioSignal *envelope_audio_signal;
-
-  AgsAudioSignal *source;
-  AgsNote *note;
+  GList *note;
   
   AgsComplex *attack;
   AgsComplex *decay;
@@ -318,15 +248,19 @@ ags_envelope_audio_signal_run_inter(AgsRecall *recall)
 
   GList *stream_source;
 
-  gdouble current_volume, current_ratio;
-
   guint frame_count;
   guint buffer_size;
+  gdouble delay;
+  gdouble fixed_length;
+  gdouble current_volume, current_ratio;
 
   guint i, j;
 
+  gboolean use_note_length, use_fixed_length;
+
   GValue audio_value = {0,};
   GValue channel_value = {0,};
+  GValue value = {0,};
 
   auto gdouble ags_envelope_audio_signal_run_inter_get_ratio(guint x0, gdouble y0,
 							     guint x1, gdouble y1);
@@ -355,6 +289,7 @@ ags_envelope_audio_signal_run_inter(AgsRecall *recall)
 
   AGS_RECALL_CLASS(ags_envelope_audio_signal_parent_class)->run_inter(recall);
 
+  envelope_channel = AGS_ENVELOPE_CHANNEL(AGS_RECALL_CHANNEL_RUN(recall->parent->parent)->recall_channel);
   envelope_audio_signal = AGS_ENVELOPE_AUDIO_SIGNAL(recall);
 
   source = AGS_RECALL_AUDIO_SIGNAL(envelope_audio_signal)->source;
@@ -366,183 +301,224 @@ ags_envelope_audio_signal_run_inter(AgsRecall *recall)
     return;
   }
 
+  /* get use note length port */
+  g_value_init(&value,
+	       G_TYPE_BOOLEAN);
+  ags_port_safe_read(envelope_channel->use_note_length,
+		     &value);
+  
+  use_note_length = g_value_get_boolean(&value);
+  g_value_unset(&value);
+
+  /* get use fixed length port */
+  g_value_init(&value,
+	       G_TYPE_BOOLEAN);
+  ags_port_safe_read(envelope_channel->use_fixed_length,
+		     &value);
+  
+  use_fixed_length = g_value_get_boolean(&value);
+  g_value_unset(&value);
+
+  note = source->note;
+
   /* initialize some control values */
-  frame_count = envelope_audio_signal->frame_count;
-
-  if(source->note != NULL &&
-     (AGS_NOTE_ENVELOPE & (AGS_NOTE(source->note)->flags)) != 0){
-    gdouble x0, y0;
-    gdouble x1, y1;
-    guint start_position;
-    guint start_frame, first_frame, buffer_size;
-    guint current_frame, current_buffer_size;
-    guint offset, prev_offset;
+  delay = ags_soundcard_get_delay(AGS_SOUNDCARD(source->soundcard));
+  buffer_size = source->buffer_size;
     
-    note = source->note;
+  while(note != NULL){
+    if((AGS_NOTE_ENVELOPE & (AGS_NOTE(note->data)->flags)) != 0){
+      AgsNote *current;
+      
+      gdouble x0, y0;
+      gdouble x1, y1;
+      guint start_position;
+      guint start_frame, first_frame, buffer_size;
+      guint current_frame, current_buffer_size;
+      guint offset, prev_offset;
+      
+      /* set frame count */
+      if(use_note_length){
+	frame_count = (AGS_NOTE(note->data)->x[1] - AGS_NOTE(note->data)->x[0]) * (delay * buffer_size);
+      }else if(use_fixed_length){
+	g_value_init(&value,
+		     G_TYPE_DOUBLE);
 
-    attack = &(note->attack);
-    decay = &(note->decay);
-    sustain = &(note->sustain);
-    release = &(note->release);
+	ags_port_safe_read(envelope_channel->fixed_length,
+			   &value);
 
-    ratio = &(note->ratio);
+	fixed_length = g_value_get_double(&value);
+	g_value_unset(&value);
 
-    /* get offsets */
-    start_position = g_list_position(source->stream_beginning,
-				     source->stream_current);
+	frame_count = fixed_length * (delay * buffer_size);
+      }
 
-    if(start_position == 0){
-      start_frame = 0;
-      first_frame = source->first_frame;
-      buffer_size = source->buffer_size - source->first_frame;
-    }else{
-      start_frame = start_position * source->buffer_size - source->first_frame;
-      first_frame = 0;
-      buffer_size = source->buffer_size;
-    }
+      current = note->data;
+      
+      attack = &(current->attack);
+      decay = &(current->decay);
+      sustain = &(current->sustain);
+      release = &(current->release);
 
-    /* attack */
-    x0 = 0.0;
-    y0 = ratio[0][1];
+      ratio = &(current->ratio);
 
-    x1 = attack[0][0];
-    y1 = attack[0][1] + ratio[0][1];
+      /* get offsets */
+      start_position = floor((delay * current->rt_offset) / frame_count);
 
-    offset = x1 * frame_count;
-    current_frame = first_frame;
-    
-    if(offset >= start_frame){
-      if(current_frame + x1 * frame_count > buffer_size){
-	current_buffer_size = buffer_size - current_frame;
+      if(start_position == 0){
+	start_frame = 0;
+	first_frame = source->first_frame;
+	buffer_size = source->buffer_size - source->first_frame;
       }else{
-	if(x1 * frame_count > buffer_size){
-	  current_buffer_size = buffer_size;
+	start_frame = start_position * source->buffer_size - source->first_frame;
+	first_frame = 0;
+	buffer_size = source->buffer_size;
+      }
+
+      /* attack */
+      x0 = 0.0;
+      y0 = ratio[0][1];
+
+      x1 = attack[0][0];
+      y1 = attack[0][1] + ratio[0][1];
+
+      offset = x1 * frame_count;
+      current_frame = first_frame;
+    
+      if(offset >= start_frame){
+	if(current_frame + x1 * frame_count > buffer_size){
+	  current_buffer_size = buffer_size - current_frame;
 	}else{
-	  current_buffer_size = x1 * frame_count;
+	  if(x1 * frame_count > buffer_size){
+	    current_buffer_size = buffer_size;
+	  }else{
+	    current_buffer_size = x1 * frame_count;
+	  }
 	}
-      }
       
-      current_ratio = ags_envelope_audio_signal_run_inter_get_ratio(0, y0,
-								    x1 * frame_count, y1);
-      current_volume = ags_envelope_audio_signal_run_inter_get_volume(y0, current_ratio,
-								      0, start_frame,
-								      x1 * frame_count);
-      ags_audio_buffer_util_envelope(stream_source->data + current_frame, 1,
-				     ags_audio_buffer_util_format_from_soundcard(source->format),
-				     current_buffer_size,
-				     current_volume,
-				     current_ratio);
-
-      current_frame += current_buffer_size;
-    }
+	current_ratio = ags_envelope_audio_signal_run_inter_get_ratio(0, y0,
+								      x1 * frame_count, y1);
+	current_volume = ags_envelope_audio_signal_run_inter_get_volume(y0, current_ratio,
+									0, start_frame,
+									x1 * frame_count);
+	ags_audio_buffer_util_envelope(stream_source->data + current_frame, 1,
+				       ags_audio_buffer_util_format_from_soundcard(source->format),
+				       current_buffer_size,
+				       current_volume,
+				       current_ratio);
+
+	current_frame += current_buffer_size;
+      }
     
-    /* decay */
-    x0 = *attack[0];
-    y0 = *attack[1] + ratio[0][1];
+      /* decay */
+      x0 = *attack[0];
+      y0 = *attack[1] + ratio[0][1];
 
-    x1 = *decay[0];
-    y1 = *decay[1] + ratio[0][1];
+      x1 = *decay[0];
+      y1 = *decay[1] + ratio[0][1];
 
-    prev_offset = offset;
-    offset += (x1 * frame_count);
+      prev_offset = offset;
+      offset += (x1 * frame_count);
 
-    if(offset >= start_frame &&
-       prev_offset < start_frame + buffer_size){
-      if(current_frame + x1 * frame_count > buffer_size){
-	current_buffer_size = buffer_size - current_frame;
-      }else{
-	if(x1 * frame_count > buffer_size){
-	  current_buffer_size = buffer_size;
+      if(offset >= start_frame &&
+	 prev_offset < start_frame + buffer_size){
+	if(current_frame + x1 * frame_count > buffer_size){
+	  current_buffer_size = buffer_size - current_frame;
 	}else{
-	  current_buffer_size = x1 * frame_count;
+	  if(x1 * frame_count > buffer_size){
+	    current_buffer_size = buffer_size;
+	  }else{
+	    current_buffer_size = x1 * frame_count;
+	  }
 	}
-      }
       
-      current_ratio = ags_envelope_audio_signal_run_inter_get_ratio(0, y0,
-								    x1 * frame_count, y1);
-      current_volume = ags_envelope_audio_signal_run_inter_get_volume(y0, current_ratio,
-								      0, prev_offset + current_frame,
-								      x1 * frame_count);
-      ags_audio_buffer_util_envelope(stream_source->data + current_frame, 1,
-				     ags_audio_buffer_util_format_from_soundcard(source->format),
-				     current_buffer_size,
-				     current_volume,
-				     current_ratio);
-
-      current_frame += current_buffer_size;
-    }
+	current_ratio = ags_envelope_audio_signal_run_inter_get_ratio(0, y0,
+								      x1 * frame_count, y1);
+	current_volume = ags_envelope_audio_signal_run_inter_get_volume(y0, current_ratio,
+									0, prev_offset + current_frame,
+									x1 * frame_count);
+	ags_audio_buffer_util_envelope(stream_source->data + current_frame, 1,
+				       ags_audio_buffer_util_format_from_soundcard(source->format),
+				       current_buffer_size,
+				       current_volume,
+				       current_ratio);
+
+	current_frame += current_buffer_size;
+      }
 
-    /* sustain */
-    x0 = *decay[0];
-    y0 = *decay[1] + ratio[0][1];
+      /* sustain */
+      x0 = *decay[0];
+      y0 = *decay[1] + ratio[0][1];
 
-    x1 = *sustain[0];
-    y1 = *sustain[1] + ratio[0][1];
+      x1 = *sustain[0];
+      y1 = *sustain[1] + ratio[0][1];
 
-    prev_offset = offset;
-    offset += (x1 * frame_count);
+      prev_offset = offset;
+      offset += (x1 * frame_count);
 
-    if(offset >= start_frame &&
-       prev_offset < start_frame + buffer_size){
-      if(current_frame + x1 * frame_count > buffer_size){
-	current_buffer_size = buffer_size - current_frame;
-      }else{
-	if(x1 * frame_count > buffer_size){
-	  current_buffer_size = buffer_size;
+      if(offset >= start_frame &&
+	 prev_offset < start_frame + buffer_size){
+	if(current_frame + x1 * frame_count > buffer_size){
+	  current_buffer_size = buffer_size - current_frame;
 	}else{
-	  current_buffer_size = x1 * frame_count;
+	  if(x1 * frame_count > buffer_size){
+	    current_buffer_size = buffer_size;
+	  }else{
+	    current_buffer_size = x1 * frame_count;
+	  }
 	}
-      }
       
-      current_ratio = ags_envelope_audio_signal_run_inter_get_ratio(0, y0,
-								    x1 * frame_count, y1);
-      current_volume = ags_envelope_audio_signal_run_inter_get_volume(y0, current_ratio,
-								      0, prev_offset + current_frame,
-								      x1 * frame_count);
-      ags_audio_buffer_util_envelope(stream_source->data + current_frame, 1,
-				     ags_audio_buffer_util_format_from_soundcard(source->format),
-				     current_buffer_size,
-				     current_volume,
-				     current_ratio);
-
-      current_frame += current_buffer_size;
-    }
+	current_ratio = ags_envelope_audio_signal_run_inter_get_ratio(0, y0,
+								      x1 * frame_count, y1);
+	current_volume = ags_envelope_audio_signal_run_inter_get_volume(y0, current_ratio,
+									0, prev_offset + current_frame,
+									x1 * frame_count);
+	ags_audio_buffer_util_envelope(stream_source->data + current_frame, 1,
+				       ags_audio_buffer_util_format_from_soundcard(source->format),
+				       current_buffer_size,
+				       current_volume,
+				       current_ratio);
+
+	current_frame += current_buffer_size;
+      }
     
-    /* release */
-    x0 = *sustain[0];
-    y0 = *sustain[1] + ratio[0][1];
+      /* release */
+      x0 = *sustain[0];
+      y0 = *sustain[1] + ratio[0][1];
 
-    x1 = *release[0];
-    y1 = *release[1] + ratio[0][1];
+      x1 = *release[0];
+      y1 = *release[1] + ratio[0][1];
 
-    prev_offset = offset;
-    offset += (x1 * frame_count);
+      prev_offset = offset;
+      offset += (x1 * frame_count);
     
-    if(offset >= start_frame &&
-       prev_offset < start_frame + buffer_size){
-      if(current_frame + x1 * frame_count > buffer_size){
-	current_buffer_size = buffer_size - current_frame;
-      }else{
-	if(x1 * frame_count > buffer_size){
-	  current_buffer_size = buffer_size;
+      if(offset >= start_frame &&
+	 prev_offset < start_frame + buffer_size){
+	if(current_frame + x1 * frame_count > buffer_size){
+	  current_buffer_size = buffer_size - current_frame;
 	}else{
-	  current_buffer_size = x1 * frame_count;
+	  if(x1 * frame_count > buffer_size){
+	    current_buffer_size = buffer_size;
+	  }else{
+	    current_buffer_size = x1 * frame_count;
+	  }
 	}
-      }
       
-      current_ratio = ags_envelope_audio_signal_run_inter_get_ratio(0, y0,
-								    x1 * frame_count, y1);
-      current_volume = ags_envelope_audio_signal_run_inter_get_volume(y0, current_ratio,
-								      0, prev_offset + current_frame,
-								      x1 * frame_count);
-      ags_audio_buffer_util_envelope(stream_source->data + current_frame, 1,
-				     ags_audio_buffer_util_format_from_soundcard(source->format),
-				     current_buffer_size,
-				     current_volume,
-				     current_ratio);
-
-      current_frame += current_buffer_size;
+	current_ratio = ags_envelope_audio_signal_run_inter_get_ratio(0, y0,
+								      x1 * frame_count, y1);
+	current_volume = ags_envelope_audio_signal_run_inter_get_volume(y0, current_ratio,
+									0, prev_offset + current_frame,
+									x1 * frame_count);
+	ags_audio_buffer_util_envelope(stream_source->data + current_frame, 1,
+				       ags_audio_buffer_util_format_from_soundcard(source->format),
+				       current_buffer_size,
+				       current_volume,
+				       current_ratio);
+
+	current_frame += current_buffer_size;
+      }
     }
+
+    note = note->next;
   }
 }
 
diff --git a/ags/audio/recall/ags_feed_audio_signal.c b/ags/audio/recall/ags_feed_audio_signal.c
index 3efc128..75ba8dd 100644
--- a/ags/audio/recall/ags_feed_audio_signal.c
+++ b/ags/audio/recall/ags_feed_audio_signal.c
@@ -20,10 +20,7 @@
 #include <ags/audio/recall/ags_feed_audio_signal.h>
 #include <ags/audio/recall/ags_feed_channel.h>
 
-#include <ags/lib/ags_parameter.h>
-
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_dynamic_connectable.h>
+#include <ags/libags.h>
 
 #include <ags/audio/ags_recall_channel_run.h>
 
@@ -204,8 +201,12 @@ ags_feed_audio_signal_run_pre(AgsRecall *recall)
 
   AGS_RECALL_CLASS(ags_feed_audio_signal_parent_class)->run_pre(recall);
 
+  if(recall->rt_safe){
+    return;
+  }
+  
   audio_signal = AGS_RECALL_AUDIO_SIGNAL(recall)->source;
-  note = audio_signal->note;
+  note = audio_signal->note->data;
 
   template = NULL;
   
@@ -223,7 +224,8 @@ ags_feed_audio_signal_run_pre(AgsRecall *recall)
 
     /* feed audio signal */
     frame_count = (guint) (((gdouble) audio_signal->samplerate / notation_delay) * (gdouble) (note->x[1] - note->x[0]));
-    
+
+    //FIXME:JK: not thread-safe
     ags_audio_signal_feed(audio_signal,
 			  template,
 			  frame_count);
diff --git a/ags/audio/recall/ags_play_dssi_audio_run.c b/ags/audio/recall/ags_play_dssi_audio_run.c
index a168ac9..998d45a 100644
--- a/ags/audio/recall/ags_play_dssi_audio_run.c
+++ b/ags/audio/recall/ags_play_dssi_audio_run.c
@@ -380,8 +380,7 @@ ags_play_dssi_audio_run_set_property(GObject *gobject,
 	return;
       }
 
-      if(count_beats_audio_run != NULL &&
-	 (AGS_RECALL_TEMPLATE & (AGS_RECALL(count_beats_audio_run)->flags)) != 0){
+      if((AGS_RECALL_TEMPLATE & (AGS_RECALL(play_dssi_audio_run)->flags)) != 0){
 	is_template = TRUE;
       }else{
 	is_template = FALSE;
diff --git a/ags/audio/recall/ags_play_notation_audio_run.c b/ags/audio/recall/ags_play_notation_audio_run.c
index 984cd29..7bafee7 100644
--- a/ags/audio/recall/ags_play_notation_audio_run.c
+++ b/ags/audio/recall/ags_play_notation_audio_run.c
@@ -173,7 +173,7 @@ ags_play_notation_audio_run_class_init(AgsPlayNotationAudioRunClass *play_notati
    *
    * The delay audio run dependency.
    * 
-   * Since: 1.0.0.7
+   * Since: 1.0.0
    */
   param_spec = g_param_spec_object("delay-audio-run",
 				   i18n_pspec("assigned AgsDelayAudioRun"),
@@ -189,7 +189,7 @@ ags_play_notation_audio_run_class_init(AgsPlayNotationAudioRunClass *play_notati
    *
    * The count beats audio run dependency.
    * 
-   * Since: 1.0.0.7
+   * Since: 1.0.0
    */
   param_spec = g_param_spec_object("count-beats-audio-run",
 				   i18n_pspec("assigned AgsCountBeatsAudioRun"),
@@ -205,7 +205,7 @@ ags_play_notation_audio_run_class_init(AgsPlayNotationAudioRunClass *play_notati
    *
    * The notation containing the notes.
    * 
-   * Since: 1.0.0.7
+   * Since: 1.0.0
    */
   param_spec = g_param_spec_object("notation",
 				   i18n_pspec("assigned AgsNotation"),
@@ -294,8 +294,7 @@ ags_play_notation_audio_run_set_property(GObject *gobject,
 	return;
       }
 
-      if(delay_audio_run != NULL &&
-	 (AGS_RECALL_TEMPLATE & (AGS_RECALL(delay_audio_run)->flags)) != 0){
+      if((AGS_RECALL_TEMPLATE & (AGS_RECALL(play_notation_audio_run)->flags)) != 0){
 	is_template = TRUE;
       }else{
 	is_template = FALSE;
@@ -346,8 +345,7 @@ ags_play_notation_audio_run_set_property(GObject *gobject,
 	return;
       }
 
-      if(count_beats_audio_run != NULL &&
-	 (AGS_RECALL_TEMPLATE & (AGS_RECALL(count_beats_audio_run)->flags)) != 0){
+      if((AGS_RECALL_TEMPLATE & (AGS_RECALL(play_notation_audio_run)->flags)) != 0){
 	is_template = TRUE;
       }else{
 	is_template = FALSE;
@@ -853,7 +851,9 @@ ags_play_notation_audio_run_alloc_input_callback(AgsDelayAudioRun *delay_audio_r
 #ifdef AGS_DEBUG	
 	g_message("playing[%u|%u]: %u | %u\n", audio_channel, selected_channel->pad, note->x[0], note->y);
 #endif
-
+	
+	note->rt_attack = attack;
+	
 	while(recycling != selected_channel->last_recycling->next){
 	  /* lookup recycling mutex */
 	  pthread_mutex_lock(application_mutex);
@@ -863,51 +863,73 @@ ags_play_notation_audio_run_alloc_input_callback(AgsDelayAudioRun *delay_audio_r
 	
 	  pthread_mutex_unlock(application_mutex);
 
-	  /* create audio signal */
-	  audio_signal = ags_audio_signal_new((GObject *) soundcard,
-					      (GObject *) recycling,
-					      (GObject *) child_recall_id);
-	  g_object_set(audio_signal,
-		       "note", note,
-		       NULL);
+	  if(!AGS_RECALL(play_notation_audio_run)->rt_safe){
+	    /* create audio signal */
+	    audio_signal = ags_audio_signal_new((GObject *) soundcard,
+						(GObject *) recycling,
+						(GObject *) child_recall_id);
+	    g_object_set(audio_signal,
+			 "note", note,
+			 NULL);
 	  
-	  if((AGS_AUDIO_PATTERN_MODE & (audio->flags)) != 0){
-	    ags_recycling_create_audio_signal_with_defaults(recycling,
-							    audio_signal,
-							    0.0, 0);
-	  }else{
-	    gdouble notation_delay;
+	    if((AGS_AUDIO_PATTERN_MODE & (audio->flags)) != 0){
+	      ags_recycling_create_audio_signal_with_defaults(recycling,
+							      audio_signal,
+							      0.0, 0);
+	    }else{
+	      gdouble notation_delay;
+
+	      GValue value = {0,};
+
+	      /* get notation delay */
+	      g_value_init(&value,
+			   G_TYPE_DOUBLE);
+	      ags_port_safe_read(delay_audio->notation_delay,
+				 &value);
+
+	      notation_delay = g_value_get_double(&value);
+	      g_value_unset(&value);
+
+	      /* create audio signal with frame count */
+	      ags_recycling_create_audio_signal_with_frame_count(recycling,
+								 audio_signal,
+								 (guint) (((gdouble) samplerate / notation_delay) * (gdouble) (note->x[1] - note->x[0])),
+								 0.0, 0);
+	    }
+	  
+	    ags_connectable_connect(AGS_CONNECTABLE(audio_signal));
 
-	    GValue value = {0,};
+	    audio_signal->stream_current = audio_signal->stream_beginning;
 
-	    /* get notation delay */
-	    g_value_init(&value,
-			 G_TYPE_DOUBLE);
-	    ags_port_safe_read(delay_audio->notation_delay,
-			       &value);
+	    /* lock and add */
+	    ags_recycling_add_audio_signal(recycling,
+					   audio_signal);
+	    //	g_object_unref(audio_signal);
+	  }else{
+	    GList *list;
+
+	    pthread_mutex_lock(recycling_mutex);
+	    
+	    audio_signal = NULL;
+	    list = ags_audio_signal_get_by_recall_id(recycling->audio_signal,
+						     child_recall_id);
+	    
+	    if(list != NULL){
+	      audio_signal = list->data;
+
+	      g_object_set(audio_signal,
+			   "note", note,
+			   NULL);
+	    }
 
-	    notation_delay = g_value_get_double(&value);
-	    g_value_unset(&value);
+	    note->rt_offset = 0;
 
-	    /* create audio signal with frame count */
-	    ags_recycling_create_audio_signal_with_frame_count(recycling,
-							       audio_signal,
-							       (guint) (((gdouble) samplerate / notation_delay) * (gdouble) (note->x[1] - note->x[0])),
-							       0.0, 0);
+	    pthread_mutex_unlock(recycling_mutex);
 	  }
 	  
-	  ags_connectable_connect(AGS_CONNECTABLE(audio_signal));
-
-	  audio_signal->stream_current = audio_signal->stream_beginning;
-
-	  /* lock and add */
-	  pthread_mutex_lock(recycling_mutex);
-
-	  ags_recycling_add_audio_signal(recycling,
-					 audio_signal);
-	  //	g_object_unref(audio_signal);
-
 	  /* iterate */
+	  pthread_mutex_lock(recycling_mutex);
+	  
 	  recycling = recycling->next;
 
 	  pthread_mutex_unlock(recycling_mutex);
@@ -915,7 +937,7 @@ ags_play_notation_audio_run_alloc_input_callback(AgsDelayAudioRun *delay_audio_r
       }else if(note_x0 > notation_counter){
 	break;
       }
-    
+      
       pthread_mutex_lock(audio_mutex);
     
       current_position = current_position->next;
diff --git a/ags/audio/recall/ags_record_midi_audio.c b/ags/audio/recall/ags_record_midi_audio.c
index 0a29491..bf5593f 100644
--- a/ags/audio/recall/ags_record_midi_audio.c
+++ b/ags/audio/recall/ags_record_midi_audio.c
@@ -1,5 +1,5 @@
 /* GSequencer - Advanced GTK Sequencer
- * Copyright (C) 2005-2015 Joël Krähemann
+ * Copyright (C) 2005-2017 Joël Krähemann
  *
  * This file is part of GSequencer.
  *
@@ -19,7 +19,7 @@
 
 #include <ags/audio/recall/ags_record_midi_audio.h>
 
-#include <ags/object/ags_plugin.h>
+#include <ags/libags.h>
 
 #include <ags/i18n.h>
 
@@ -120,6 +120,7 @@ void
 ags_record_midi_audio_class_init(AgsRecordMidiAudioClass *record_midi_audio)
 {
   GObjectClass *gobject;
+
   GParamSpec *param_spec;
 
   ags_record_midi_audio_parent_class = g_type_class_peek_parent(record_midi_audio);
@@ -139,7 +140,7 @@ ags_record_midi_audio_class_init(AgsRecordMidiAudioClass *record_midi_audio)
    * 
    * The playback port.
    * 
-   * Since: 1.0.0.7
+   * Since: 1.0.0
    */
   param_spec = g_param_spec_object("playback",
 				   i18n_pspec("if do playback"),
@@ -155,7 +156,7 @@ ags_record_midi_audio_class_init(AgsRecordMidiAudioClass *record_midi_audio)
    * 
    * The record port.
    * 
-   * Since: 1.0.0.7
+   * Since: 1.0.0
    */
   param_spec = g_param_spec_object("record",
 				   i18n_pspec("if do record"),
@@ -171,7 +172,7 @@ ags_record_midi_audio_class_init(AgsRecordMidiAudioClass *record_midi_audio)
    * 
    * The filename port.
    * 
-   * Since: 1.0.0.7
+   * Since: 1.0.0
    */
   param_spec = g_param_spec_object("filename",
 				   i18n_pspec("filename of record"),
@@ -187,7 +188,7 @@ ags_record_midi_audio_class_init(AgsRecordMidiAudioClass *record_midi_audio)
    * 
    * The division port.
    * 
-   * Since: 1.0.0.7
+   * Since: 1.0.0
    */
   param_spec = g_param_spec_object("division",
 				   i18n_pspec("division of record"),
@@ -203,7 +204,7 @@ ags_record_midi_audio_class_init(AgsRecordMidiAudioClass *record_midi_audio)
    * 
    * The tempo port.
    * 
-   * Since: 1.0.0.7
+   * Since: 1.0.0
    */
   param_spec = g_param_spec_object("tempo",
 				   i18n_pspec("tempo of record"),
@@ -219,7 +220,7 @@ ags_record_midi_audio_class_init(AgsRecordMidiAudioClass *record_midi_audio)
    * 
    * The bpm port.
    * 
-   * Since: 1.0.0.7
+   * Since: 1.0.0
    */
   param_spec = g_param_spec_object("bpm",
 				   i18n_pspec("bpm of record"),
diff --git a/ags/audio/recall/ags_record_midi_audio.h b/ags/audio/recall/ags_record_midi_audio.h
index 549799c..3b0c984 100644
--- a/ags/audio/recall/ags_record_midi_audio.h
+++ b/ags/audio/recall/ags_record_midi_audio.h
@@ -1,5 +1,5 @@
 /* GSequencer - Advanced GTK Sequencer
- * Copyright (C) 2005-2015 Joël Krähemann
+ * Copyright (C) 2005-2017 Joël Krähemann
  *
  * This file is part of GSequencer.
  *
diff --git a/ags/audio/recall/ags_record_midi_audio_run.c b/ags/audio/recall/ags_record_midi_audio_run.c
index 99b707a..2a33548 100644
--- a/ags/audio/recall/ags_record_midi_audio_run.c
+++ b/ags/audio/recall/ags_record_midi_audio_run.c
@@ -319,8 +319,7 @@ ags_record_midi_audio_run_set_property(GObject *gobject,
 	return;
       }
 
-      if(count_beats_audio_run != NULL &&
-	 (AGS_RECALL_TEMPLATE & (AGS_RECALL(count_beats_audio_run)->flags)) != 0){
+      if((AGS_RECALL_TEMPLATE & (AGS_RECALL(record_midi_audio_run)->flags)) != 0){
 	is_template = TRUE;
       }else{
 	is_template = FALSE;
@@ -401,6 +400,10 @@ ags_record_midi_audio_run_dispose(GObject *gobject)
     record_midi_audio_run->count_beats_audio_run = NULL;
   }
 
+  g_list_free_full(record_midi_audio_run->note,
+		   g_object_unref);
+  record_midi_audio_run->note = NULL;
+  
   /* call parent */
   G_OBJECT_CLASS(ags_record_midi_audio_run_parent_class)->dispose(gobject);
 }
@@ -427,6 +430,9 @@ ags_record_midi_audio_run_finalize(GObject *gobject)
     g_object_unref(G_OBJECT(record_midi_audio_run->timestamp));
   }
 
+  g_list_free_full(record_midi_audio_run->note,
+		   g_object_unref);
+
   /* call parent */
   G_OBJECT_CLASS(ags_record_midi_audio_run_parent_class)->finalize(gobject);
 }
@@ -963,6 +969,8 @@ ags_record_midi_audio_run_run_pre(AgsRecall *recall)
 		  if(!pattern_mode){
 		    record_midi_audio_run->note = g_list_prepend(record_midi_audio_run->note,
 								 current_note);
+		    g_object_ref(current_note);
+		    
 		    pthread_mutex_lock(audio_mutex);
 
 		    current_note->flags |= AGS_NOTE_FEED;
@@ -999,6 +1007,7 @@ ags_record_midi_audio_run_run_pre(AgsRecall *recall)
 
 		  record_midi_audio_run->note = g_list_remove(record_midi_audio_run->note,
 							      current_note);
+		  g_object_unref(current_note);
 		}else{
 		  pthread_mutex_lock(audio_mutex);
 
@@ -1052,6 +1061,7 @@ ags_record_midi_audio_run_run_pre(AgsRecall *recall)
 	      
 	      record_midi_audio_run->note = g_list_remove(record_midi_audio_run->note,
 							  current_note);
+	      g_object_unref(current_note);
 
 #ifdef AGS_DEBUG
 	      g_message("remove %d", current_note->y);
diff --git a/ags/audio/recall/ags_record_midi_audio_run.h b/ags/audio/recall/ags_record_midi_audio_run.h
index 2106cbf..345624a 100644
--- a/ags/audio/recall/ags_record_midi_audio_run.h
+++ b/ags/audio/recall/ags_record_midi_audio_run.h
@@ -1,5 +1,5 @@
 /* GSequencer - Advanced GTK Sequencer
- * Copyright (C) 2005-2015 Joël Krähemann
+ * Copyright (C) 2005-2017 Joël Krähemann
  *
  * This file is part of GSequencer.
  *
diff --git a/ags/audio/recall/ags_route_dssi_audio_run.c b/ags/audio/recall/ags_route_dssi_audio_run.c
index e2204ee..cf42bf3 100644
--- a/ags/audio/recall/ags_route_dssi_audio_run.c
+++ b/ags/audio/recall/ags_route_dssi_audio_run.c
@@ -341,8 +341,7 @@ ags_route_dssi_audio_run_set_property(GObject *gobject,
 	return;
       }
 
-      if(count_beats_audio_run != NULL &&
-	 (AGS_RECALL_TEMPLATE & (AGS_RECALL(count_beats_audio_run)->flags)) != 0){
+      if((AGS_RECALL_TEMPLATE & (AGS_RECALL(route_dssi_audio_run)->flags)) != 0){
 	is_template = TRUE;
       }else{
 	is_template = FALSE;
@@ -890,34 +889,29 @@ ags_route_dssi_audio_run_feed_midi(AgsRecall *recall,
 	    while(dssi != NULL){
 	      recall_dssi_run = AGS_RECALL_DSSI_RUN(dssi->data);
 	    
-	      if(recall_dssi_run->event_buffer == NULL){
+	      if(AGS_RECALL(recall_dssi_run)->rt_safe ||
+		 recall_dssi_run->event_buffer == NULL){
 		/* prepend note */
 		//		route_dssi_audio_run->feed_midi = g_list_prepend(route_dssi_audio_run->feed_midi,
 		//						 note);
 	      
 		recall_dssi_run->route_dssi_audio_run = (GObject *) route_dssi_audio_run;
-	      
+
 		/* key on */
-		seq_event = (snd_seq_event_t *) malloc(sizeof(snd_seq_event_t));
-		memset(seq_event, 0, sizeof(snd_seq_event_t));
-		//memset(seq_event, 0, sizeof(snd_seq_event_t));
-	      
+		seq_event = recall_dssi_run->event_buffer[0];
+		
 		seq_event->type = SND_SEQ_EVENT_NOTEON;
 
 		seq_event->data.note.channel = 0;
 		seq_event->data.note.note = 0x7f & (selected_channel->pad - audio_start_mapping + midi_start_mapping);
 		seq_event->data.note.velocity = 127;
 
-		AGS_RECALL_AUDIO_SIGNAL(recall_dssi_run)->audio_channel = audio_channel;
-		recall_dssi_run->note = (GObject *) note;
-		  
-		recall_dssi_run->event_buffer = (snd_seq_event_t **) malloc(2 * sizeof(snd_seq_event_t *));
-		recall_dssi_run->event_buffer[0] = seq_event;
-		recall_dssi_run->event_buffer[1] = NULL;
-		  
-		recall_dssi_run->event_count = (unsigned long *) malloc(2 * sizeof(unsigned long));
 		recall_dssi_run->event_count[0] = 1;
-		recall_dssi_run->event_count[1] = 0;
+		  
+		AGS_RECALL_AUDIO_SIGNAL(recall_dssi_run)->audio_channel = audio_channel;
+		recall_dssi_run->note = g_list_prepend(recall_dssi_run->note,
+						       (GObject *) note);
+		g_object_ref(note);
 	      }
 
 	      //fixme:jk: remove notes
diff --git a/ags/audio/recall/ags_route_lv2_audio_run.c b/ags/audio/recall/ags_route_lv2_audio_run.c
index dd8b9ff..6bf4d34 100644
--- a/ags/audio/recall/ags_route_lv2_audio_run.c
+++ b/ags/audio/recall/ags_route_lv2_audio_run.c
@@ -897,7 +897,8 @@ ags_route_lv2_audio_run_feed_midi(AgsRecall *recall,
 	    while(lv2 != NULL){
 	      recall_lv2_run = AGS_RECALL_LV2_RUN(lv2->data);
 	    
-	      if(recall_lv2_run->note == NULL){
+	      if(AGS_RECALL(recall_lv2_run)->rt_safe ||
+		 recall_lv2_run->note == NULL){
 		/* prepend note */
 		//		route_lv2_audio_run->feed_midi = g_list_prepend(route_lv2_audio_run->feed_midi,
 		//						note);
@@ -915,8 +916,10 @@ ags_route_lv2_audio_run_feed_midi(AgsRecall *recall,
 		seq_event->data.note.velocity = 127;
 
 		AGS_RECALL_AUDIO_SIGNAL(recall_lv2_run)->audio_channel = audio_channel;
-		recall_lv2_run->note = (GObject *) note;
-
+		recall_lv2_run->note = g_list_prepend(recall_lv2_run->note,
+						      (GObject *) note);
+		g_object_ref(note);
+		
 		/* write to port */
 		if((AGS_RECALL_LV2_HAS_ATOM_PORT & (recall_lv2->flags)) != 0){
 		  ags_lv2_plugin_atom_sequence_append_midi(recall_lv2_run->atom_port,
diff --git a/ags/audio/recall/ags_rt_stream_audio_signal.c b/ags/audio/recall/ags_rt_stream_audio_signal.c
new file mode 100644
index 0000000..f66343d
--- /dev/null
+++ b/ags/audio/recall/ags_rt_stream_audio_signal.c
@@ -0,0 +1,541 @@
+/* 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/recall/ags_rt_stream_channel.h>
+#include <ags/audio/recall/ags_rt_stream_channel_run.h>
+#include <ags/audio/recall/ags_rt_stream_recycling.h>
+#include <ags/audio/recall/ags_rt_stream_audio_signal.h>
+
+#include <ags/libags.h>
+
+#include <ags/audio/ags_audio_buffer_util.h>
+
+#include <ags/audio/task/ags_unref_audio_signal.h>
+
+void ags_rt_stream_audio_signal_class_init(AgsRtStreamAudioSignalClass *rt_stream_audio_signal);
+void ags_rt_stream_audio_signal_connectable_interface_init(AgsConnectableInterface *connectable);
+void ags_rt_stream_audio_signal_dynamic_connectable_interface_init(AgsDynamicConnectableInterface *dynamic_connectable);
+void ags_rt_stream_audio_signal_init(AgsRtStreamAudioSignal *rt_stream_audio_signal);
+void ags_rt_stream_audio_signal_connect(AgsConnectable *connectable);
+void ags_rt_stream_audio_signal_disconnect(AgsConnectable *connectable);
+void ags_rt_stream_audio_signal_connect_dynamic(AgsDynamicConnectable *dynamic_connectable);
+void ags_rt_stream_audio_signal_disconnect_dynamic(AgsDynamicConnectable *dynamic_connectable);
+void ags_rt_stream_audio_signal_dispose(GObject *gobject);
+void ags_rt_stream_audio_signal_finalize(GObject *gobject);
+
+void ags_rt_stream_audio_signal_run_init_pre(AgsRecall *recall);
+void ags_rt_stream_audio_signal_run_pre(AgsRecall *recall);
+AgsRecall* ags_rt_stream_audio_signal_duplicate(AgsRecall *recall,
+						AgsRecallID *recall_id,
+						guint *n_params, GParameter *parameter);
+
+/**
+ * SECTION:ags_rt_stream_audio_signal
+ * @short_description: rt_streams audio signal
+ * @title: AgsRtStreamAudioSignal
+ * @section_id:
+ * @include: ags/audio/recall/ags_rt_stream_audio_signal.h
+ *
+ * The #AgsRtStreamAudioSignal class streams the audio signal template.
+ */
+
+static gpointer ags_rt_stream_audio_signal_parent_class = NULL;
+static AgsConnectableInterface *ags_rt_stream_audio_signal_parent_connectable_interface;
+static AgsDynamicConnectableInterface *ags_rt_stream_audio_signal_parent_dynamic_connectable_interface;
+
+GType
+ags_rt_stream_audio_signal_get_type()
+{
+  static GType ags_type_rt_stream_audio_signal = 0;
+
+  if(!ags_type_rt_stream_audio_signal){
+    static const GTypeInfo ags_rt_stream_audio_signal_info = {
+      sizeof (AgsRtStreamAudioSignalClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      (GClassInitFunc) ags_rt_stream_audio_signal_class_init,
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof (AgsRtStreamAudioSignal),
+      0,    /* n_preallocs */
+      (GInstanceInitFunc) ags_rt_stream_audio_signal_init,
+    };
+
+    static const GInterfaceInfo ags_connectable_interface_info = {
+      (GInterfaceInitFunc) ags_rt_stream_audio_signal_connectable_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };
+
+    static const GInterfaceInfo ags_dynamic_connectable_interface_info = {
+      (GInterfaceInitFunc) ags_rt_stream_audio_signal_dynamic_connectable_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };
+
+    ags_type_rt_stream_audio_signal = g_type_register_static(AGS_TYPE_RECALL_AUDIO_SIGNAL,
+							     "AgsRtStreamAudioSignal",
+							     &ags_rt_stream_audio_signal_info,
+							     0);
+
+    g_type_add_interface_static(ags_type_rt_stream_audio_signal,
+				AGS_TYPE_CONNECTABLE,
+				&ags_connectable_interface_info);
+
+    g_type_add_interface_static(ags_type_rt_stream_audio_signal,
+				AGS_TYPE_DYNAMIC_CONNECTABLE,
+				&ags_dynamic_connectable_interface_info);
+  }
+
+  return (ags_type_rt_stream_audio_signal);
+}
+
+void
+ags_rt_stream_audio_signal_class_init(AgsRtStreamAudioSignalClass *rt_stream_audio_signal)
+{
+  GObjectClass *gobject;
+  AgsRecallClass *recall;
+  GParamSpec *param_spec;
+
+  ags_rt_stream_audio_signal_parent_class = g_type_class_peek_parent(rt_stream_audio_signal);
+
+  /* GObjectClass */
+  gobject = (GObjectClass *) rt_stream_audio_signal;
+
+  gobject->dispose = ags_rt_stream_audio_signal_dispose;
+  gobject->finalize = ags_rt_stream_audio_signal_finalize;
+
+  /* AgsRecallClass */
+  recall = (AgsRecallClass *) rt_stream_audio_signal;
+
+  recall->run_init_pre = ags_rt_stream_audio_signal_run_init_pre;
+  recall->run_pre = ags_rt_stream_audio_signal_run_pre;
+  recall->duplicate = ags_rt_stream_audio_signal_duplicate;
+}
+
+void
+ags_rt_stream_audio_signal_connectable_interface_init(AgsConnectableInterface *connectable)
+{
+  ags_rt_stream_audio_signal_parent_connectable_interface = g_type_interface_peek_parent(connectable);
+
+  connectable->connect = ags_rt_stream_audio_signal_connect;
+  connectable->disconnect = ags_rt_stream_audio_signal_disconnect;
+}
+
+void
+ags_rt_stream_audio_signal_dynamic_connectable_interface_init(AgsDynamicConnectableInterface *dynamic_connectable)
+{
+  ags_rt_stream_audio_signal_parent_dynamic_connectable_interface = g_type_interface_peek_parent(dynamic_connectable);
+
+  dynamic_connectable->connect_dynamic = ags_rt_stream_audio_signal_connect_dynamic;
+  dynamic_connectable->disconnect_dynamic = ags_rt_stream_audio_signal_disconnect_dynamic;
+}
+
+void
+ags_rt_stream_audio_signal_init(AgsRtStreamAudioSignal *rt_stream_audio_signal)
+{
+  AGS_RECALL(rt_stream_audio_signal)->name = "ags-rt_stream";
+  AGS_RECALL(rt_stream_audio_signal)->version = AGS_RECALL_DEFAULT_VERSION;
+  AGS_RECALL(rt_stream_audio_signal)->build_id = AGS_RECALL_DEFAULT_BUILD_ID;
+  AGS_RECALL(rt_stream_audio_signal)->xml_type = "ags-rt_stream-audio-signal";
+  AGS_RECALL(rt_stream_audio_signal)->port = NULL;
+
+  AGS_RECALL(rt_stream_audio_signal)->child_type = G_TYPE_NONE;
+
+  rt_stream_audio_signal->dispose_source = NULL;
+}
+
+void
+ags_rt_stream_audio_signal_dispose(GObject *gobject)
+{
+  AGS_RT_STREAM_AUDIO_SIGNAL(gobject)->dispose_source = AGS_RECALL_AUDIO_SIGNAL(gobject)->source;
+
+  /* call parent */
+  G_OBJECT_CLASS(ags_rt_stream_audio_signal_parent_class)->dispose(gobject); 
+}
+
+void
+ags_rt_stream_audio_signal_finalize(GObject *gobject)
+{
+  AgsAudioSignal *audio_signal;
+
+  audio_signal = AGS_RT_STREAM_AUDIO_SIGNAL(gobject)->dispose_source;
+  
+  if(audio_signal != NULL){
+    AgsRecycling *recycling;
+
+    recycling = audio_signal->recycling;
+    
+    if(recycling != NULL){
+      ags_recycling_remove_audio_signal(recycling,
+					audio_signal);
+    }
+    
+    g_object_run_dispose(audio_signal);
+    g_object_unref(audio_signal);
+  }
+
+  /* call parent */
+  G_OBJECT_CLASS(ags_rt_stream_audio_signal_parent_class)->finalize(gobject); 
+}
+
+void
+ags_rt_stream_audio_signal_connect(AgsConnectable *connectable)
+{
+  if((AGS_RECALL_CONNECTED & (AGS_RECALL(connectable)->flags)) != 0){
+    return;
+  }
+
+  /* call parent */
+  ags_rt_stream_audio_signal_parent_connectable_interface->connect(connectable);
+
+  /* empty */
+}
+
+void
+ags_rt_stream_audio_signal_disconnect(AgsConnectable *connectable)
+{
+  /* call parent */
+  ags_rt_stream_audio_signal_parent_connectable_interface->disconnect(connectable);
+
+  /* empty */
+}
+
+void
+ags_rt_stream_audio_signal_connect_dynamic(AgsDynamicConnectable *dynamic_connectable)
+{
+  if((AGS_RECALL_DYNAMIC_CONNECTED & (AGS_RECALL(dynamic_connectable)->flags)) != 0){
+    return;
+  }
+
+  /* call parent */
+  ags_rt_stream_audio_signal_parent_dynamic_connectable_interface->connect_dynamic(dynamic_connectable);
+
+  /* empty */
+}
+
+void
+ags_rt_stream_audio_signal_disconnect_dynamic(AgsDynamicConnectable *dynamic_connectable)
+{
+  /* call parent */
+  ags_rt_stream_audio_signal_parent_dynamic_connectable_interface->disconnect_dynamic(dynamic_connectable);
+
+  /* empty */
+}
+
+void
+ags_rt_stream_audio_signal_run_init_pre(AgsRecall *recall)
+{
+  /* call parent */
+  AGS_RECALL_CLASS(ags_rt_stream_audio_signal_parent_class)->run_init_pre(recall);
+
+  //  g_message("rt_stream");
+}
+
+void
+ags_rt_stream_audio_signal_run_pre(AgsRecall *recall)
+{
+  AgsRtStreamAudioSignal *rt_stream_audio_signal;
+
+  AgsRecycling *recycling;
+  AgsAudioSignal *source;
+  AgsAudioSignal *template;
+
+  AgsMutexManager *mutex_manager;
+
+  GList *note;
+
+  void *buffer;
+
+  gdouble delay;
+  guint buffer_size;
+  guint copy_mode;
+
+  pthread_mutex_t *application_mutex;
+  pthread_mutex_t *soundcard_mutex;
+  pthread_mutex_t *recycling_mutex;
+
+  mutex_manager = ags_mutex_manager_get_instance();
+  application_mutex = ags_mutex_manager_get_application_mutex(mutex_manager);
+
+  AGS_RECALL_CLASS(ags_rt_stream_audio_signal_parent_class)->run_inter(recall);
+
+  rt_stream_audio_signal = AGS_RT_STREAM_AUDIO_SIGNAL(recall);
+
+  source = AGS_RECALL_AUDIO_SIGNAL(rt_stream_audio_signal)->source;
+
+  buffer = source->stream_beginning->data;
+  buffer_size = source->buffer_size;
+
+  /* lookup soundcard mutex */
+  pthread_mutex_lock(application_mutex);
+
+  soundcard_mutex = ags_mutex_manager_lookup(mutex_manager,
+					     (GObject *) source->soundcard);
+	
+  pthread_mutex_unlock(application_mutex);
+  
+  pthread_mutex_lock(soundcard_mutex);
+
+  delay = ags_soundcard_get_delay(AGS_SOUNDCARD(source->soundcard));
+
+  pthread_mutex_unlock(soundcard_mutex);
+
+  /* lookup recycling mutex */
+  recycling = source->recycling;
+
+  pthread_mutex_lock(application_mutex);
+
+  recycling_mutex = ags_mutex_manager_lookup(mutex_manager,
+					     (GObject *) recycling);
+	
+  pthread_mutex_unlock(application_mutex);
+
+  /* get template */
+  pthread_mutex_lock(recycling_mutex);
+  
+  template = ags_audio_signal_get_template(recycling->audio_signal);
+  
+  note = source->note;
+  
+  ags_audio_buffer_util_clear_buffer(buffer, 1,
+				     buffer_size, ags_audio_buffer_util_format_from_soundcard(source->format));
+
+  copy_mode = ags_audio_buffer_util_get_copy_mode(ags_audio_buffer_util_format_from_soundcard(source->format),
+						  ags_audio_buffer_util_format_from_soundcard(template->format));
+
+  while(note != NULL){
+    AgsNote *current;
+
+    GList *stream, *template_stream;
+
+    guint64 offset;
+    
+    current = note->data;
+    offset = current->rt_offset;
+    
+    if(offset < delay * current->x[1] ||
+       offset < template->length){
+      if(template->loop_start < template->loop_end){
+	guint frame_count;
+	guint loop_length;
+	guint loop_frame_count;
+	guint n_frames;
+	guint copy_n_frames;
+	guint nth_loop;
+	guint j_start;
+	guint i, j, k;
+
+	frame_count = delay * (AGS_NOTE(note->data)->x[1] - AGS_NOTE(note->data)->x[0]) * buffer_size;
+	
+	loop_length = template->loop_end - template->loop_start;
+	loop_frame_count = ((frame_count - template->loop_start) / loop_length) * template->buffer_size;
+
+	if(offset * buffer_size > template->loop_end){
+	  if(((guint) offset * buffer_size) + buffer_size > frame_count - (template->frame_count - template->loop_end)){
+	    if(offset * buffer_size > frame_count - (template->frame_count - template->loop_end)){
+	      j_start = (frame_count - (offset * buffer_size)) % buffer_size;
+
+	      template_stream = g_list_nth(template->stream_beginning,
+					   (frame_count - (offset * buffer_size)) / buffer_size);
+
+	      if(template_stream == NULL){
+		note = note->next;
+
+		continue;
+	      }	      
+	    }else{
+	      j_start = ((guint) (offset * buffer_size) - template->loop_end) % (template->loop_end - template->loop_start) % buffer_size;
+
+	      template_stream = g_list_nth(template->stream_beginning,
+					   (template->loop_start + ((((guint) (offset * buffer_size) - template->loop_end) % (template->loop_end - template->loop_start)) / buffer_size)));
+
+	      if(template_stream == NULL){
+		note = note->next;
+
+		continue;
+	      }
+	    }
+	  }else{
+	    j_start = ((guint) (offset * buffer_size) - template->loop_end) % (template->loop_end - template->loop_start) % buffer_size;
+	    
+	    template_stream = g_list_nth(template->stream_beginning,
+					 (template->loop_start + ((((guint) (offset * buffer_size) - template->loop_end) % (template->loop_end - template->loop_start)) / buffer_size)));
+
+	    if(template_stream == NULL){
+	      note = note->next;
+
+	      continue;
+	    }
+	  }
+	}else{
+	  j_start = ((guint) (offset * buffer_size)) % buffer_size;
+
+	  template_stream = g_list_nth(template->stream_beginning,
+				       offset);
+
+	  if(template_stream == NULL){
+	    note = note->next;
+
+	    continue;
+	  }
+	}
+
+	if(offset == 0){
+	  k = AGS_NOTE(note->data)->rt_attack;
+	}else{
+	  k = 0;
+	}
+	
+	for(i = 0, j = j_start, nth_loop = offset; i < buffer_size;){
+	  /* compute count of frames to copy */
+	  copy_n_frames = buffer_size;
+
+	  /* limit nth loop */
+	  if(i > template->loop_start &&
+	     i + copy_n_frames > template->loop_start + loop_length &&
+	     i + copy_n_frames < template->loop_start + loop_frame_count &&
+	     i + copy_n_frames >= template->loop_start + (nth_loop + 1) * loop_length){
+	    copy_n_frames = (template->loop_start + (nth_loop + 1) * loop_length) - i;
+	  }
+
+	  /* check boundaries */
+	  if((k % buffer_size) + copy_n_frames > buffer_size){
+	    copy_n_frames = buffer_size - (k % buffer_size);
+	  }
+
+	  if(j + copy_n_frames > buffer_size){
+	    copy_n_frames = buffer_size - j;
+	  }
+
+	  if(buffer == NULL ||
+	     template_stream == NULL){
+	    break;
+	  }
+    
+	  /* copy */
+	  ags_audio_buffer_util_copy_buffer_to_buffer(buffer, 1, k % buffer_size,
+						      template_stream->data, 1, j,
+						      copy_n_frames, copy_mode);
+
+	  /* increment and iterate */
+	  if((i + copy_n_frames) % buffer_size == 0){
+	    break;
+	  }
+
+	  if(j + copy_n_frames == template->buffer_size){
+	    template_stream = template_stream->next;
+	  }
+    
+	  if(template_stream == NULL ||
+	     (i > template->loop_start &&
+	      i + copy_n_frames > template->loop_start + loop_length &&
+	      i + copy_n_frames < template->loop_start + loop_frame_count &&
+	      i + copy_n_frames >= template->loop_start + (nth_loop + 1) * loop_length)){
+	    j = template->loop_start % template->buffer_size;
+	    template_stream = g_list_nth(template->stream_beginning,
+					 floor(template->loop_start / template->buffer_size));
+
+	    nth_loop++;
+	  }else{
+	    j += copy_n_frames;
+	  }
+    
+	  i += copy_n_frames;
+	  k += copy_n_frames;
+
+	  if(j == template->buffer_size){
+	    j = 0;
+	  }
+	}
+	
+      }else{
+	template_stream = g_list_nth(template->stream_beginning,
+			    offset);
+
+	if(template_stream == NULL){
+	  note = note->next;
+
+	  continue;
+	}
+	
+	if(offset == 0){
+	  ags_audio_buffer_util_copy_buffer_to_buffer(buffer, 1, AGS_NOTE(note->data)->rt_attack,
+						      template_stream->data, 1, 0,
+						      buffer_size - AGS_NOTE(note->data)->rt_attack, copy_mode);
+	}else{
+	  if(AGS_NOTE(note->data)->rt_attack != 0 && template_stream->prev != NULL){
+	    ags_audio_buffer_util_copy_buffer_to_buffer(buffer, 1, 0,
+							template_stream->prev->data, 1, buffer_size - AGS_NOTE(note->data)->rt_attack,
+							AGS_NOTE(note->data)->rt_attack, copy_mode);
+	  }
+
+	  ags_audio_buffer_util_copy_buffer_to_buffer(buffer, 1, AGS_NOTE(note->data)->rt_attack,
+						      template_stream->data, 1, 0,
+						      buffer_size - AGS_NOTE(note->data)->rt_attack, copy_mode);	  
+	}
+      }
+    }else{
+      ags_audio_signal_remove_note(source,
+				   current);
+    }
+
+    current->rt_offset += 1;
+    
+    note = note->next;
+  }
+
+  pthread_mutex_unlock(recycling_mutex);
+}
+
+AgsRecall*
+ags_rt_stream_audio_signal_duplicate(AgsRecall *recall,
+				     AgsRecallID *recall_id,
+				     guint *n_params, GParameter *parameter)
+{
+  AgsRtStreamAudioSignal *copy;
+
+  copy = (AgsRtStreamAudioSignal *) AGS_RECALL_CLASS(ags_rt_stream_audio_signal_parent_class)->duplicate(recall,
+													 recall_id,
+													 n_params, parameter);
+
+  return((AgsRecall *) copy);
+}
+
+/**
+ * ags_rt_stream_audio_signal_new:
+ * @audio_signal: an #AgsAudioSignal
+ *
+ * Creates an #AgsRtStreamAudioSignal
+ *
+ * Returns: a new #AgsRtStreamAudioSignal
+ *
+ * Since: 1.4.0
+ */
+AgsRtStreamAudioSignal*
+ags_rt_stream_audio_signal_new(AgsAudioSignal *audio_signal)
+{
+  AgsRtStreamAudioSignal *rt_stream_audio_signal;
+
+  rt_stream_audio_signal = (AgsRtStreamAudioSignal *) g_object_new(AGS_TYPE_RT_STREAM_AUDIO_SIGNAL,
+								   "source", audio_signal,
+								   NULL);
+
+  return(rt_stream_audio_signal);
+}
diff --git a/ags/audio/recall/ags_rt_stream_audio_signal.h b/ags/audio/recall/ags_rt_stream_audio_signal.h
new file mode 100644
index 0000000..8aed1c0
--- /dev/null
+++ b/ags/audio/recall/ags_rt_stream_audio_signal.h
@@ -0,0 +1,54 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2018 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_RT_STREAM_AUDIO_SIGNAL_H__
+#define __AGS_RT_STREAM_AUDIO_SIGNAL_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <ags/audio/ags_recall_audio_signal.h>
+
+#define AGS_TYPE_RT_STREAM_AUDIO_SIGNAL                (ags_rt_stream_audio_signal_get_type())
+#define AGS_RT_STREAM_AUDIO_SIGNAL(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_RT_STREAM_AUDIO_SIGNAL, AgsRtStreamAudioSignal))
+#define AGS_RT_STREAM_AUDIO_SIGNAL_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_RT_STREAM_AUDIO_SIGNAL, AgsRtStreamAudioSignalClass))
+#define AGS_IS_RT_STREAM_AUDIO_SIGNAL(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AGS_TYPE_RT_STREAM_AUDIO_SIGNAL))
+#define AGS_IS_RT_STREAM_AUDIO_SIGNAL_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_RT_STREAM_AUDIO_SIGNAL))
+#define AGS_RT_STREAM_AUDIO_SIGNAL_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), AGS_TYPE_RT_STREAM_AUDIO_SIGNAL, AgsRtStreamAudioSignalClass))
+
+typedef struct _AgsRtStreamAudioSignal AgsRtStreamAudioSignal;
+typedef struct _AgsRtStreamAudioSignalClass AgsRtStreamAudioSignalClass;
+
+struct _AgsRtStreamAudioSignal
+{
+  AgsRecallAudioSignal recall_audio_signal;
+
+  GObject *dispose_source;
+};
+
+struct _AgsRtStreamAudioSignalClass
+{
+  AgsRecallAudioSignalClass recall_audio_signal;
+};
+
+GType ags_rt_stream_audio_signal_get_type();
+
+AgsRtStreamAudioSignal* ags_rt_stream_audio_signal_new(AgsAudioSignal *audio_signal);
+
+#endif /*__AGS_RT_STREAM_AUDIO_SIGNAL_H__*/
diff --git a/ags/audio/recall/ags_rt_stream_channel.c b/ags/audio/recall/ags_rt_stream_channel.c
new file mode 100644
index 0000000..35f354b
--- /dev/null
+++ b/ags/audio/recall/ags_rt_stream_channel.c
@@ -0,0 +1,201 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2018 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/recall/ags_rt_stream_channel.h>
+
+#include <ags/libags.h>
+
+#include <ags/i18n.h>
+
+void ags_rt_stream_channel_class_init(AgsRtStreamChannelClass *rt_stream_channel);
+void ags_rt_stream_channel_connectable_interface_init(AgsConnectableInterface *connectable);
+void ags_rt_stream_channel_plugin_interface_init(AgsPluginInterface *plugin);
+void ags_rt_stream_channel_init(AgsRtStreamChannel *rt_stream_channel);
+void ags_rt_stream_channel_connect(AgsConnectable *connectable);
+void ags_rt_stream_channel_disconnect(AgsConnectable *connectable);
+void ags_rt_stream_channel_set_ports(AgsPlugin *plugin, GList *port);
+void ags_rt_stream_channel_dispose(GObject *gobject);
+void ags_rt_stream_channel_finalize(GObject *gobject);
+
+/**
+ * SECTION:ags_rt_stream_channel
+ * @short_description: rt_streams channel
+ * @title: AgsRtStreamChannel
+ * @section_id:
+ * @include: ags/audio/recall/ags_rt_stream_channel.h
+ *
+ * The #AgsRtStreamChannel class provides ports to the effect processor.
+ */
+
+static gpointer ags_rt_stream_channel_parent_class = NULL;
+static AgsConnectableInterface *ags_rt_stream_channel_parent_connectable_interface;
+static AgsPluginInterface *ags_rt_stream_channel_parent_plugin_interface;
+
+static const gchar *ags_rt_stream_channel_plugin_name = "ags-rt-stream";
+
+GType
+ags_rt_stream_channel_get_type()
+{
+  static GType ags_type_rt_stream_channel = 0;
+
+  if(!ags_type_rt_stream_channel){
+    static const GTypeInfo ags_rt_stream_channel_info = {
+      sizeof (AgsRtStreamChannelClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      (GClassInitFunc) ags_rt_stream_channel_class_init,
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof (AgsRtStreamChannel),
+      0,    /* n_preallocs */
+      (GInstanceInitFunc) ags_rt_stream_channel_init,
+    };
+
+    static const GInterfaceInfo ags_connectable_interface_info = {
+      (GInterfaceInitFunc) ags_rt_stream_channel_connectable_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };
+
+    static const GInterfaceInfo ags_plugin_interface_info = {
+      (GInterfaceInitFunc) ags_rt_stream_channel_plugin_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };    
+
+    ags_type_rt_stream_channel = g_type_register_static(AGS_TYPE_RECALL_CHANNEL,
+							"AgsRtStreamChannel",
+							&ags_rt_stream_channel_info,
+							0);
+
+    g_type_add_interface_static(ags_type_rt_stream_channel,
+				AGS_TYPE_CONNECTABLE,
+				&ags_connectable_interface_info);
+
+    g_type_add_interface_static(ags_type_rt_stream_channel,
+				AGS_TYPE_PLUGIN,
+				&ags_plugin_interface_info);
+  }
+
+  return (ags_type_rt_stream_channel);
+}
+
+void
+ags_rt_stream_channel_class_init(AgsRtStreamChannelClass *rt_stream_channel)
+{
+  GObjectClass *gobject;
+  AgsRecallClass *recall;
+  GParamSpec *param_spec;
+
+  ags_rt_stream_channel_parent_class = g_type_class_peek_parent(rt_stream_channel);
+
+  /* GObjectClass */
+  gobject = (GObjectClass *) rt_stream_channel;
+
+  gobject->dispose = ags_rt_stream_channel_dispose;
+  gobject->finalize = ags_rt_stream_channel_finalize;
+}
+
+void
+ags_rt_stream_channel_connectable_interface_init(AgsConnectableInterface *connectable)
+{
+  ags_rt_stream_channel_parent_connectable_interface = g_type_interface_peek_parent(connectable);
+
+  connectable->connect = ags_rt_stream_channel_connect;
+  connectable->disconnect = ags_rt_stream_channel_disconnect;
+}
+
+void
+ags_rt_stream_channel_plugin_interface_init(AgsPluginInterface *plugin)
+{
+  ags_rt_stream_channel_parent_plugin_interface = g_type_interface_peek_parent(plugin);
+}
+
+void
+ags_rt_stream_channel_init(AgsRtStreamChannel *rt_stream_channel)
+{
+  AgsConfig *config;
+  
+  AGS_RECALL(rt_stream_channel)->name = "ags-rt-stream";
+  AGS_RECALL(rt_stream_channel)->version = AGS_RECALL_DEFAULT_VERSION;
+  AGS_RECALL(rt_stream_channel)->build_id = AGS_RECALL_DEFAULT_BUILD_ID;
+  AGS_RECALL(rt_stream_channel)->xml_type = "ags-rt-stream-channel";
+}
+
+void
+ags_rt_stream_channel_dispose(GObject *gobject)
+{
+  AgsRtStreamChannel *rt_stream_channel;
+
+  rt_stream_channel = AGS_RT_STREAM_CHANNEL(gobject);
+
+  /* call parent */
+  G_OBJECT_CLASS(ags_rt_stream_channel_parent_class)->dispose(gobject);
+}
+
+void
+ags_rt_stream_channel_finalize(GObject *gobject)
+{
+  AgsRtStreamChannel *rt_stream_channel;
+
+  rt_stream_channel = AGS_RT_STREAM_CHANNEL(gobject);
+
+  /* call parent */
+  G_OBJECT_CLASS(ags_rt_stream_channel_parent_class)->finalize(gobject);
+}
+
+void
+ags_rt_stream_channel_connect(AgsConnectable *connectable)
+{
+  if((AGS_RECALL_CONNECTED & (AGS_RECALL(connectable)->flags)) != 0){
+    return;
+  }
+
+  ags_rt_stream_channel_parent_connectable_interface->connect(connectable);
+
+  /* empty */
+}
+
+void
+ags_rt_stream_channel_disconnect(AgsConnectable *connectable)
+{
+  ags_rt_stream_channel_parent_connectable_interface->disconnect(connectable);
+
+  /* empty */
+}
+
+/**
+ * ags_rt_stream_channel_new:
+ *
+ * Creates an #AgsRtStreamChannel
+ *
+ * Returns: a new #AgsRtStreamChannel
+ *
+ * Since: 1.4.0
+ */
+AgsRtStreamChannel*
+ags_rt_stream_channel_new()
+{
+  AgsRtStreamChannel *rt_stream_channel;
+
+  rt_stream_channel = (AgsRtStreamChannel *) g_object_new(AGS_TYPE_RT_STREAM_CHANNEL,
+							  NULL);
+
+  return(rt_stream_channel);
+}
diff --git a/ags/audio/recall/ags_rt_stream_channel.h b/ags/audio/recall/ags_rt_stream_channel.h
new file mode 100644
index 0000000..3385752
--- /dev/null
+++ b/ags/audio/recall/ags_rt_stream_channel.h
@@ -0,0 +1,52 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2018 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_RT_STREAM_CHANNEL_H__
+#define __AGS_RT_STREAM_CHANNEL_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <ags/audio/ags_recall_channel.h>
+
+#define AGS_TYPE_RT_STREAM_CHANNEL                (ags_rt_stream_channel_get_type())
+#define AGS_RT_STREAM_CHANNEL(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_RT_STREAM_CHANNEL, AgsRtStreamChannel))
+#define AGS_RT_STREAM_CHANNEL_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_RT_STREAM_CHANNEL, AgsRtStreamChannelClass))
+#define AGS_IS_RT_STREAM_CHANNEL(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AGS_TYPE_RT_STREAM_CHANNEL))
+#define AGS_IS_RT_STREAM_CHANNEL_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_RT_STREAM_CHANNEL))
+#define AGS_RT_STREAM_CHANNEL_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), AGS_TYPE_RT_STREAM_CHANNEL, AgsRtStreamChannelClass))
+
+typedef struct _AgsRtStreamChannel AgsRtStreamChannel;
+typedef struct _AgsRtStreamChannelClass AgsRtStreamChannelClass;
+
+struct _AgsRtStreamChannel
+{
+  AgsRecallChannel recall_channel;
+};
+
+struct _AgsRtStreamChannelClass
+{
+  AgsRecallChannelClass recall_channel;
+};
+
+GType ags_rt_stream_channel_get_type();
+
+AgsRtStreamChannel* ags_rt_stream_channel_new();
+
+#endif /*__AGS_RT_STREAM_CHANNEL_H__*/
diff --git a/ags/audio/recall/ags_rt_stream_channel_run.c b/ags/audio/recall/ags_rt_stream_channel_run.c
new file mode 100644
index 0000000..4e64e79
--- /dev/null
+++ b/ags/audio/recall/ags_rt_stream_channel_run.c
@@ -0,0 +1,316 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2018 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/recall/ags_rt_stream_channel_run.h>
+#include <ags/audio/recall/ags_rt_stream_recycling.h>
+
+#include <ags/libags.h>
+
+#include <ags/audio/ags_audio.h>
+#include <ags/audio/ags_recycling.h>
+#include <ags/audio/ags_recall_id.h>
+
+#include <ags/audio/task/ags_cancel_recall.h>
+
+void ags_rt_stream_channel_run_class_init(AgsRtStreamChannelRunClass *rt_stream_channel_run);
+void ags_rt_stream_channel_run_connectable_interface_init(AgsConnectableInterface *connectable);
+void ags_rt_stream_channel_run_dynamic_connectable_interface_init(AgsDynamicConnectableInterface *dynamic_connectable);
+void ags_rt_stream_channel_run_plugin_interface_init(AgsPluginInterface *plugin);
+void ags_rt_stream_channel_run_init(AgsRtStreamChannelRun *rt_stream_channel_run);
+void ags_rt_stream_channel_run_connect(AgsConnectable *connectable);
+void ags_rt_stream_channel_run_disconnect(AgsConnectable *connectable);
+void ags_rt_stream_channel_run_connect_dynamic(AgsDynamicConnectable *dynamic_connectable);
+void ags_rt_stream_channel_run_disconnect_dynamic(AgsDynamicConnectable *dynamic_connectable);
+void ags_rt_stream_channel_run_finalize(GObject *gobject);
+
+void ags_rt_stream_channel_run_check_rt_stream(AgsRecall *recall);
+AgsRecall* ags_rt_stream_channel_run_duplicate(AgsRecall *recall,
+					       AgsRecallID *recall_id,
+					       guint *n_params, GParameter *parameter);
+
+/**
+ * SECTION:ags_rt_stream_channel_run
+ * @short_description: rt_streams channel
+ * @title: AgsRtStreamChannelRun
+ * @section_id:
+ * @include: ags/audio/recall/ags_rt_stream_channel_run.h
+ *
+ * The #AgsRtStreamChannelRun class streams the audio signal template.
+ */
+
+static gpointer ags_rt_stream_channel_run_parent_class = NULL;
+static AgsConnectableInterface *ags_rt_stream_channel_run_parent_connectable_interface;
+static AgsDynamicConnectableInterface *ags_rt_stream_channel_run_parent_dynamic_connectable_interface;
+static AgsPluginInterface *ags_rt_stream_channel_run_parent_plugin_interface;
+
+GType
+ags_rt_stream_channel_run_get_type()
+{
+  static GType ags_type_rt_stream_channel_run = 0;
+
+  if(!ags_type_rt_stream_channel_run){
+    static const GTypeInfo ags_rt_stream_channel_run_info = {
+      sizeof (AgsRtStreamChannelRunClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      (GClassInitFunc) ags_rt_stream_channel_run_class_init,
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof (AgsRtStreamChannelRun),
+      0,    /* n_preallocs */
+      (GInstanceInitFunc) ags_rt_stream_channel_run_init,
+    };
+
+    static const GInterfaceInfo ags_connectable_interface_info = {
+      (GInterfaceInitFunc) ags_rt_stream_channel_run_connectable_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };
+
+    static const GInterfaceInfo ags_dynamic_connectable_interface_info = {
+      (GInterfaceInitFunc) ags_rt_stream_channel_run_dynamic_connectable_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };
+
+    static const GInterfaceInfo ags_plugin_interface_info = {
+      (GInterfaceInitFunc) ags_rt_stream_channel_run_plugin_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };    
+
+    ags_type_rt_stream_channel_run = g_type_register_static(AGS_TYPE_RECALL_CHANNEL_RUN,
+							    "AgsRtStreamChannelRun",
+							    &ags_rt_stream_channel_run_info,
+							    0);
+
+    g_type_add_interface_static(ags_type_rt_stream_channel_run,
+				AGS_TYPE_CONNECTABLE,
+				&ags_connectable_interface_info);
+
+    g_type_add_interface_static(ags_type_rt_stream_channel_run,
+				AGS_TYPE_DYNAMIC_CONNECTABLE,
+				&ags_dynamic_connectable_interface_info);
+
+    g_type_add_interface_static(ags_type_rt_stream_channel_run,
+				AGS_TYPE_PLUGIN,
+				&ags_plugin_interface_info);
+  }
+
+  return (ags_type_rt_stream_channel_run);
+}
+
+void
+ags_rt_stream_channel_run_class_init(AgsRtStreamChannelRunClass *rt_stream_channel_run)
+{
+  GObjectClass *gobject;
+  AgsRecallClass *recall;
+
+  ags_rt_stream_channel_run_parent_class = g_type_class_peek_parent(rt_stream_channel_run);
+
+  /* GObjectClass */
+  gobject = (GObjectClass *) rt_stream_channel_run;
+
+  gobject->finalize = ags_rt_stream_channel_run_finalize;
+
+  /* AgsRecallClass */
+  recall = (AgsRecallClass *) rt_stream_channel_run;
+
+  recall->check_rt_stream = ags_rt_stream_channel_run_check_rt_stream;
+  recall->duplicate = ags_rt_stream_channel_run_duplicate;
+}
+
+void
+ags_rt_stream_channel_run_connectable_interface_init(AgsConnectableInterface *connectable)
+{
+  ags_rt_stream_channel_run_parent_connectable_interface = g_type_interface_peek_parent(connectable);
+
+  connectable->connect = ags_rt_stream_channel_run_connect;
+  connectable->disconnect = ags_rt_stream_channel_run_disconnect;
+}
+
+void
+ags_rt_stream_channel_run_dynamic_connectable_interface_init(AgsDynamicConnectableInterface *dynamic_connectable)
+{
+  ags_rt_stream_channel_run_parent_dynamic_connectable_interface = g_type_interface_peek_parent(dynamic_connectable);
+
+  dynamic_connectable->connect_dynamic = ags_rt_stream_channel_run_connect_dynamic;
+  dynamic_connectable->disconnect_dynamic = ags_rt_stream_channel_run_disconnect_dynamic;
+}
+
+void
+ags_rt_stream_channel_run_plugin_interface_init(AgsPluginInterface *plugin)
+{
+  ags_rt_stream_channel_run_parent_plugin_interface = g_type_interface_peek_parent(plugin);
+}
+
+void
+ags_rt_stream_channel_run_init(AgsRtStreamChannelRun *rt_stream_channel_run)
+{
+  AGS_RECALL(rt_stream_channel_run)->name = "ags-rt_stream";
+  AGS_RECALL(rt_stream_channel_run)->version = AGS_RECALL_DEFAULT_VERSION;
+  AGS_RECALL(rt_stream_channel_run)->build_id = AGS_RECALL_DEFAULT_BUILD_ID;
+  AGS_RECALL(rt_stream_channel_run)->xml_type = "ags-rt_stream-channel-run";
+  AGS_RECALL(rt_stream_channel_run)->port = NULL;
+
+  AGS_RECALL(rt_stream_channel_run)->flags |= (AGS_RECALL_OUTPUT_ORIENTATED |
+					       AGS_RECALL_RUN_FIRST);
+  AGS_RECALL(rt_stream_channel_run)->child_type = AGS_TYPE_RT_STREAM_RECYCLING;
+}
+
+void
+ags_rt_stream_channel_run_finalize(GObject *gobject)
+{
+  /* empty */
+
+  /* call parent */
+  G_OBJECT_CLASS(ags_rt_stream_channel_run_parent_class)->finalize(gobject);
+}
+
+void
+ags_rt_stream_channel_run_connect(AgsConnectable *connectable)
+{
+  /* call parent */
+  ags_rt_stream_channel_run_parent_connectable_interface->connect(connectable);
+
+  /* empty */
+}
+
+void
+ags_rt_stream_channel_run_disconnect(AgsConnectable *connectable)
+{
+  /* call parent */
+  ags_rt_stream_channel_run_parent_connectable_interface->disconnect(connectable);
+
+  /* empty */
+}
+
+void
+ags_rt_stream_channel_run_connect_dynamic(AgsDynamicConnectable *dynamic_connectable)
+{
+  /* call parent */
+  ags_rt_stream_channel_run_parent_dynamic_connectable_interface->connect_dynamic(dynamic_connectable);
+
+  /* empty */
+}
+
+void
+ags_rt_stream_channel_run_disconnect_dynamic(AgsDynamicConnectable *dynamic_connectable)
+{
+  AgsChannel *channel;
+  AgsRtStreamChannelRun *rt_stream_channel_run;
+
+  ags_rt_stream_channel_run_parent_dynamic_connectable_interface->disconnect_dynamic(dynamic_connectable);
+
+  /* empty */
+}
+
+void
+ags_rt_stream_channel_run_check_rt_stream(AgsRecall *recall)
+{
+  AgsChannel *source;
+  AgsRecycling *first_recycling, *last_recycling;
+  AgsRecycling *recycling, *end_recycling;
+
+  AgsRtStreamChannelRun *rt_stream_channel_run;
+
+  pthread_mutex_t *recycling_mutex;
+  
+  rt_stream_channel_run = recall;
+
+  source = AGS_RECALL_CHANNEL_RUN(rt_stream_channel_run)->source;
+
+  /* get first and last recycling */
+  pthread_mutex_lock(source->obj_mutex);
+  
+  first_recycling = source->first_recycling;
+  last_recycling = source->last_recycling;
+
+  pthread_mutex_unlock(source->obj_mutex);
+
+  /* get end */
+  pthread_mutex_lock(last_recycling->obj_mutex);
+  
+  end_recycling = last_recycling->next;
+
+  pthread_mutex_unlock(last_recycling->obj_mutex);
+
+  /* */
+  recycling = first_recycling;
+  
+  while(recycling != end_recycling){
+    AgsAudioSignal *audio_signal;
+    
+    recycling_mutex = recycling->obj_mutex;
+
+    pthread_mutex_lock(recycling_mutex);
+
+    audio_signal = ags_audio_signal_new(recycling->soundcard,
+					recycling,
+					recall->recall_id);
+    ags_audio_signal_stream_resize(audio_signal,
+				   1);
+    audio_signal->stream_current = audio_signal->stream_beginning;
+    
+    pthread_mutex_unlock(recycling_mutex);
+
+    ags_recycling_add_audio_signal(recycling,
+				   audio_signal);
+
+    pthread_mutex_lock(recycling_mutex);
+    
+    recycling = recycling->next;
+    
+    pthread_mutex_unlock(recycling_mutex);
+  }
+}
+
+AgsRecall*
+ags_rt_stream_channel_run_duplicate(AgsRecall *recall,
+				    AgsRecallID *recall_id,
+				    guint *n_params, GParameter *parameter)
+{
+  AgsRtStreamChannelRun *copy;
+
+  copy = (AgsRtStreamChannelRun *) AGS_RECALL_CLASS(ags_rt_stream_channel_run_parent_class)->duplicate(recall,
+												       recall_id,
+												       n_params, parameter);
+
+  return((AgsRecall *) copy);
+}
+
+/**
+ * ags_rt_stream_channel_run_new:
+ *
+ * Creates an #AgsRtStreamChannelRun
+ *
+ * Returns: a new #AgsRtStreamChannelRun
+ *
+ * Since: 1.4.0
+ */
+AgsRtStreamChannelRun*
+ags_rt_stream_channel_run_new()
+{
+  AgsRtStreamChannelRun *rt_stream_channel_run;
+
+  rt_stream_channel_run = (AgsRtStreamChannelRun *) g_object_new(AGS_TYPE_RT_STREAM_CHANNEL_RUN,
+								 NULL);
+  
+  return(rt_stream_channel_run);
+}
diff --git a/ags/audio/recall/ags_rt_stream_channel_run.h b/ags/audio/recall/ags_rt_stream_channel_run.h
new file mode 100644
index 0000000..63edfe8
--- /dev/null
+++ b/ags/audio/recall/ags_rt_stream_channel_run.h
@@ -0,0 +1,54 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2018 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_RT_STREAM_CHANNEL_RUN_H__
+#define __AGS_RT_STREAM_CHANNEL_RUN_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <ags/audio/ags_recall_channel_run.h>
+
+#include <ags/audio/recall/ags_rt_stream_channel.h>
+
+#define AGS_TYPE_RT_STREAM_CHANNEL_RUN                (ags_rt_stream_channel_run_get_type())
+#define AGS_RT_STREAM_CHANNEL_RUN(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_RT_STREAM_CHANNEL_RUN, AgsRtStreamChannelRun))
+#define AGS_RT_STREAM_CHANNEL_RUN_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_RT_STREAM_CHANNEL_RUN, AgsRtStreamChannelRunClass))
+#define AGS_IS_RT_STREAM_CHANNEL_RUN(obj)             (G_TYPE_CHECK_INSTANCE_TYPE((obj), AGS_TYPE_RT_STREAM_CHANNEL_RUN))
+#define AGS_IS_RT_STREAM_CHANNEL_RUN_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE((class), AGS_TYPE_RT_STREAM_CHANNEL_RUN))
+#define AGS_RT_STREAM_CHANNEL_RUN_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS((obj), AGS_TYPE_RT_STREAM_CHANNEL_RUN, AgsRtStreamChannelRunClass))
+
+typedef struct _AgsRtStreamChannelRun AgsRtStreamChannelRun;
+typedef struct _AgsRtStreamChannelRunClass AgsRtStreamChannelRunClass;
+
+struct _AgsRtStreamChannelRun
+{
+  AgsRecallChannelRun recall_channel_run;
+};
+
+struct _AgsRtStreamChannelRunClass
+{
+  AgsRecallChannelRunClass recall_channel_run;
+};
+
+GType ags_rt_stream_channel_run_get_type();
+
+AgsRtStreamChannelRun* ags_rt_stream_channel_run_new();
+
+#endif /*__AGS_RT_STREAM_CHANNEL_RUN_H__*/
diff --git a/ags/audio/recall/ags_rt_stream_recycling.c b/ags/audio/recall/ags_rt_stream_recycling.c
new file mode 100644
index 0000000..974c6ae
--- /dev/null
+++ b/ags/audio/recall/ags_rt_stream_recycling.c
@@ -0,0 +1,228 @@
+/* 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/recall/ags_rt_stream_recycling.h>
+#include <ags/audio/recall/ags_rt_stream_audio_signal.h>
+
+#include <ags/libags.h>
+
+#include <ags/audio/task/ags_remove_audio_signal.h>
+
+void ags_rt_stream_recycling_class_init(AgsRtStreamRecyclingClass *rt_stream_recycling);
+void ags_rt_stream_recycling_connectable_interface_init(AgsConnectableInterface *connectable);
+void ags_rt_stream_recycling_dynamic_connectable_interface_init(AgsDynamicConnectableInterface *dynamic_connectable);
+void ags_rt_stream_recycling_init(AgsRtStreamRecycling *rt_stream_recycling);
+void ags_rt_stream_recycling_connect(AgsConnectable *connectable);
+void ags_rt_stream_recycling_disconnect(AgsConnectable *connectable);
+void ags_rt_stream_recycling_connect_dynamic(AgsDynamicConnectable *dynamic_connectable);
+void ags_rt_stream_recycling_disconnect_dynamic(AgsDynamicConnectable *dynamic_connectable);
+void ags_rt_stream_recycling_finalize(GObject *gobject);
+
+AgsRecall* ags_rt_stream_recycling_duplicate(AgsRecall *recall,
+					     AgsRecallID *recall_id,
+					     guint *n_params, GParameter *parameter);
+
+/**
+ * SECTION:ags_rt_stream_recycling
+ * @short_description: rt_streams recycling
+ * @title: AgsRtStreamRecycling
+ * @section_id:
+ * @include: ags/audio/recall/ags_rt_stream_recycling.h
+ *
+ * The #AgsRtStreamRecycling rt_streams the recycling with appropriate #AgsRecallID.
+ */
+
+static gpointer ags_rt_stream_recycling_parent_class = NULL;
+static AgsConnectableInterface *ags_rt_stream_recycling_parent_connectable_interface;
+static AgsDynamicConnectableInterface *ags_rt_stream_recycling_parent_dynamic_connectable_interface;
+
+GType
+ags_rt_stream_recycling_get_type()
+{
+  static GType ags_type_rt_stream_recycling = 0;
+
+  if(!ags_type_rt_stream_recycling){
+    static const GTypeInfo ags_rt_stream_recycling_info = {
+      sizeof (AgsRtStreamRecyclingClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      (GClassInitFunc) ags_rt_stream_recycling_class_init,
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof (AgsRtStreamRecycling),
+      0,    /* n_preallocs */
+      (GInstanceInitFunc) ags_rt_stream_recycling_init,
+    };
+
+    static const GInterfaceInfo ags_connectable_interface_info = {
+      (GInterfaceInitFunc) ags_rt_stream_recycling_connectable_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };
+
+    static const GInterfaceInfo ags_dynamic_connectable_interface_info = {
+      (GInterfaceInitFunc) ags_rt_stream_recycling_dynamic_connectable_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };
+
+    ags_type_rt_stream_recycling = g_type_register_static(AGS_TYPE_RECALL_RECYCLING,
+							  "AgsRtStreamRecycling",
+							  &ags_rt_stream_recycling_info,
+							  0);
+
+    g_type_add_interface_static(ags_type_rt_stream_recycling,
+				AGS_TYPE_CONNECTABLE,
+				&ags_connectable_interface_info);
+
+    g_type_add_interface_static(ags_type_rt_stream_recycling,
+				AGS_TYPE_DYNAMIC_CONNECTABLE,
+				&ags_dynamic_connectable_interface_info);
+  }
+
+  return (ags_type_rt_stream_recycling);
+}
+
+void
+ags_rt_stream_recycling_class_init(AgsRtStreamRecyclingClass *rt_stream_recycling)
+{
+  GObjectClass *gobject;
+  AgsRecallClass *recall;
+  GParamSpec *param_spec;
+
+  ags_rt_stream_recycling_parent_class = g_type_class_peek_parent(rt_stream_recycling);
+
+  /* GObjectClass */
+  gobject = (GObjectClass *) rt_stream_recycling;
+
+  gobject->finalize = ags_rt_stream_recycling_finalize;
+
+  /* AgsRecallClass */
+  recall = (AgsRecallClass *) rt_stream_recycling;
+
+  recall->duplicate = ags_rt_stream_recycling_duplicate;
+}
+
+void
+ags_rt_stream_recycling_connectable_interface_init(AgsConnectableInterface *connectable)
+{
+  ags_rt_stream_recycling_parent_connectable_interface = g_type_interface_peek_parent(connectable);
+
+  connectable->connect = ags_rt_stream_recycling_connect;
+  connectable->disconnect = ags_rt_stream_recycling_disconnect;
+}
+
+void
+ags_rt_stream_recycling_dynamic_connectable_interface_init(AgsDynamicConnectableInterface *dynamic_connectable)
+{
+  ags_rt_stream_recycling_parent_dynamic_connectable_interface = g_type_interface_peek_parent(dynamic_connectable);
+
+  dynamic_connectable->connect_dynamic = ags_rt_stream_recycling_connect_dynamic;
+  dynamic_connectable->disconnect_dynamic = ags_rt_stream_recycling_disconnect_dynamic;
+}
+
+void
+ags_rt_stream_recycling_init(AgsRtStreamRecycling *rt_stream_recycling)
+{
+  AGS_RECALL(rt_stream_recycling)->name = "ags-rt_stream";
+  AGS_RECALL(rt_stream_recycling)->version = AGS_RECALL_DEFAULT_VERSION;
+  AGS_RECALL(rt_stream_recycling)->build_id = AGS_RECALL_DEFAULT_BUILD_ID;
+  AGS_RECALL(rt_stream_recycling)->xml_type = "ags-rt_stream-recycling";
+  AGS_RECALL(rt_stream_recycling)->port = NULL;
+
+  AGS_RECALL(rt_stream_recycling)->child_type = AGS_TYPE_RT_STREAM_AUDIO_SIGNAL;
+
+  AGS_RECALL_RECYCLING(rt_stream_recycling)->flags |= (AGS_RECALL_RECYCLING_MAP_CHILD_SOURCE);
+}
+
+void
+ags_rt_stream_recycling_finalize(GObject *gobject)
+{
+  /* empty */
+
+  /* call parent */
+  G_OBJECT_CLASS(ags_rt_stream_recycling_parent_class)->finalize(gobject);
+}
+
+void
+ags_rt_stream_recycling_connect(AgsConnectable *connectable)
+{
+  ags_rt_stream_recycling_parent_connectable_interface->connect(connectable);
+
+  /* empty */
+}
+
+void
+ags_rt_stream_recycling_disconnect(AgsConnectable *connectable)
+{
+  ags_rt_stream_recycling_parent_connectable_interface->disconnect(connectable);
+
+  /* empty */
+}
+
+void
+ags_rt_stream_recycling_connect_dynamic(AgsDynamicConnectable *dynamic_connectable)
+{
+  AgsRtStreamRecycling *rt_stream_recycling;
+
+  ags_rt_stream_recycling_parent_dynamic_connectable_interface->connect_dynamic(dynamic_connectable);
+}
+
+void
+ags_rt_stream_recycling_disconnect_dynamic(AgsDynamicConnectable *dynamic_connectable)
+{
+  ags_rt_stream_recycling_parent_dynamic_connectable_interface->disconnect_dynamic(dynamic_connectable);
+}
+
+AgsRecall*
+ags_rt_stream_recycling_duplicate(AgsRecall *recall,
+				  AgsRecallID *recall_id,
+				  guint *n_params, GParameter *parameter)
+{
+  AgsRtStreamRecycling *copy;
+
+  copy = (AgsRtStreamRecycling *) AGS_RECALL_CLASS(ags_rt_stream_recycling_parent_class)->duplicate(recall,
+												    recall_id,
+												    n_params, parameter);
+
+
+  return((AgsRecall *) copy);
+}
+
+/**
+ * ags_rt_stream_recycling_new:
+ * @recycling: the #AgsRecycling
+ *
+ * Creates an #AgsRtStreamRecycling
+ *
+ * Returns: a new #AgsRtStreamRecycling
+ *
+ * Since: 1.4.0
+ */
+AgsRtStreamRecycling*
+ags_rt_stream_recycling_new(AgsRecycling *recycling)
+{
+  AgsRtStreamRecycling *rt_stream_recycling;
+
+  rt_stream_recycling = (AgsRtStreamRecycling *) g_object_new(AGS_TYPE_RT_STREAM_RECYCLING,
+							      "source", recycling,
+							      NULL);
+
+  return(rt_stream_recycling);
+}
diff --git a/ags/audio/recall/ags_rt_stream_recycling.h b/ags/audio/recall/ags_rt_stream_recycling.h
new file mode 100644
index 0000000..1d4f8b9
--- /dev/null
+++ b/ags/audio/recall/ags_rt_stream_recycling.h
@@ -0,0 +1,52 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2018 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_RT_STREAM_RECYCLING_H__
+#define __AGS_RT_STREAM_RECYCLING_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <ags/audio/ags_recall_recycling.h>
+
+#define AGS_TYPE_RT_STREAM_RECYCLING                (ags_rt_stream_recycling_get_type())
+#define AGS_RT_STREAM_RECYCLING(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_RT_STREAM_RECYCLING, AgsRtStreamRecycling))
+#define AGS_RT_STREAM_RECYCLING_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_RT_STREAM_RECYCLING, AgsRtStreamRecyclingClass))
+#define AGS_IS_RT_STREAM_RECYCLING(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AGS_TYPE_RT_STREAM_RECYCLING))
+#define AGS_IS_RT_STREAM_RECYCLING_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_RT_STREAM_RECYCLING))
+#define AGS_RT_STREAM_RECYCLING_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), AGS_TYPE_RT_STREAM_RECYCLING, AgsRtStreamRecyclingClass))
+
+typedef struct _AgsRtStreamRecycling AgsRtStreamRecycling;
+typedef struct _AgsRtStreamRecyclingClass AgsRtStreamRecyclingClass;
+
+struct _AgsRtStreamRecycling
+{
+  AgsRecallRecycling recall_recycling;
+};
+
+struct _AgsRtStreamRecyclingClass
+{
+  AgsRecallRecyclingClass recall_recycling;
+};
+
+GType ags_rt_stream_recycling_get_type();
+
+AgsRtStreamRecycling* ags_rt_stream_recycling_new(AgsRecycling *recycling);
+
+#endif /*__AGS_RT_STREAM_RECYCLING_H__*/
diff --git a/ags/audio/recall/ags_stream_audio_signal.c b/ags/audio/recall/ags_stream_audio_signal.c
index bc0fb6d..a2fd801 100644
--- a/ags/audio/recall/ags_stream_audio_signal.c
+++ b/ags/audio/recall/ags_stream_audio_signal.c
@@ -22,10 +22,7 @@
 #include <ags/audio/recall/ags_stream_recycling.h>
 #include <ags/audio/recall/ags_stream_audio_signal.h>
 
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_dynamic_connectable.h>
-
-#include <ags/thread/ags_mutex_manager.h>
+#include <ags/libags.h>
 
 #include <ags/audio/task/ags_unref_audio_signal.h>
 
diff --git a/ags/audio/recall/ags_stream_channel.c b/ags/audio/recall/ags_stream_channel.c
index 215709c..dfa4ad6 100644
--- a/ags/audio/recall/ags_stream_channel.c
+++ b/ags/audio/recall/ags_stream_channel.c
@@ -19,9 +19,7 @@
 
 #include <ags/audio/recall/ags_stream_channel.h>
 
-#include <ags/object/ags_config.h>
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_plugin.h>
+#include <ags/libags.h>
 
 #include <ags/i18n.h>
 
diff --git a/ags/audio/recall/ags_stream_channel_run.c b/ags/audio/recall/ags_stream_channel_run.c
index f810d0a..c06b695 100644
--- a/ags/audio/recall/ags_stream_channel_run.c
+++ b/ags/audio/recall/ags_stream_channel_run.c
@@ -20,10 +20,7 @@
 #include <ags/audio/recall/ags_stream_channel_run.h>
 #include <ags/audio/recall/ags_stream_recycling.h>
 
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_dynamic_connectable.h>
-#include <ags/object/ags_plugin.h>
-#include <ags/object/ags_soundcard.h>
+#include <ags/libags.h>
 
 #include <ags/audio/ags_audio.h>
 #include <ags/audio/ags_recycling.h>
diff --git a/ags/audio/recall/ags_stream_recycling.c b/ags/audio/recall/ags_stream_recycling.c
index 187aa78..e8f34ed 100644
--- a/ags/audio/recall/ags_stream_recycling.c
+++ b/ags/audio/recall/ags_stream_recycling.c
@@ -20,9 +20,7 @@
 #include <ags/audio/recall/ags_stream_recycling.h>
 #include <ags/audio/recall/ags_stream_audio_signal.h>
 
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_dynamic_connectable.h>
-#include <ags/object/ags_soundcard.h>
+#include <ags/libags.h>
 
 #include <ags/audio/task/ags_remove_audio_signal.h>
 
diff --git a/ags/audio/recall/ags_volume_audio_signal.c b/ags/audio/recall/ags_volume_audio_signal.c
index 233bcc3..37bc434 100644
--- a/ags/audio/recall/ags_volume_audio_signal.c
+++ b/ags/audio/recall/ags_volume_audio_signal.c
@@ -20,13 +20,11 @@
 #include <ags/audio/recall/ags_volume_audio_signal.h>
 #include <ags/audio/recall/ags_volume_channel.h>
 
-#include <ags/lib/ags_parameter.h>
+#include <ags/libags.h>
 
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_dynamic_connectable.h>
-
-#include <ags/audio/ags_recall_channel_run.h>
+#include <ags/audio/ags_input.h>
 #include <ags/audio/ags_port.h>
+#include <ags/audio/ags_recall_channel_run.h>
 #include <ags/audio/ags_audio_buffer_util.h>
 
 void ags_volume_audio_signal_class_init(AgsVolumeAudioSignalClass *volume_audio_signal);
@@ -203,6 +201,12 @@ ags_volume_audio_signal_run_inter(AgsRecall *recall)
 {
   AGS_RECALL_CLASS(ags_volume_audio_signal_parent_class)->run_inter(recall);
 
+  if(recall->rt_safe &&
+     recall->recall_id->recycling_context->parent != NULL &&
+     AGS_RECALL_AUDIO_SIGNAL(recall)->source->note == NULL){
+    return;
+  }
+  
   if(AGS_RECALL_AUDIO_SIGNAL(recall)->source->stream_current != NULL){
     AgsVolumeChannel *volume_channel;
 
diff --git a/ags/audio/task/ags_append_audio.c b/ags/audio/task/ags_append_audio.c
index 560f0e5..37e35a5 100644
--- a/ags/audio/task/ags_append_audio.c
+++ b/ags/audio/task/ags_append_audio.c
@@ -502,29 +502,29 @@ ags_append_audio_launch(AgsTask *task)
        !g_ascii_strncasecmp(str1,
 			    "channel",
 			    8)){
-      /* super threaded setup - channel */
-      if(!g_ascii_strncasecmp(str1,
-			      "channel",
-			      8)){
-	/* get some fields */
-	pthread_mutex_lock(audio_mutex);
+      /* get some fields */
+      pthread_mutex_lock(audio_mutex);
 	
-	output = audio->output;
+      output = audio->output;
 	
-	playback_domain = AGS_PLAYBACK_DOMAIN(audio->playback_domain);
+      playback_domain = AGS_PLAYBACK_DOMAIN(audio->playback_domain);
 
-	audio_thread = playback_domain->audio_thread[AGS_PLAYBACK_DOMAIN_SCOPE_SEQUENCER];
+      audio_thread = playback_domain->audio_thread[AGS_PLAYBACK_DOMAIN_SCOPE_SEQUENCER];
 	
-	pthread_mutex_unlock(audio_mutex);
+      pthread_mutex_unlock(audio_mutex);
 
-	/* parent mutex */
-	pthread_mutex_lock(application_mutex);
+      /* parent mutex */
+      pthread_mutex_lock(application_mutex);
 
-	audio_thread_mutex = ags_mutex_manager_lookup(mutex_manager,
-						      (GObject *) audio_thread);
+      audio_thread_mutex = ags_mutex_manager_lookup(mutex_manager,
+						    (GObject *) audio_thread);
   
-	pthread_mutex_unlock(application_mutex);
-
+      pthread_mutex_unlock(application_mutex);
+      
+      /* super threaded setup - channel */
+      if(!g_ascii_strncasecmp(str1,
+			      "channel",
+			      8)){
 	/* sequencer */
 	start_queue = NULL;
 	
diff --git a/ags/audio/task/ags_apply_synth.c b/ags/audio/task/ags_apply_synth.c
index 92d84a2..8ac4b7e 100644
--- a/ags/audio/task/ags_apply_synth.c
+++ b/ags/audio/task/ags_apply_synth.c
@@ -1032,6 +1032,7 @@ ags_apply_synth_launch(AgsTask *task)
 	  
 	pthread_mutex_lock(channel_mutex);
 
+	//FIXME:JK: not thread-safe
 	ags_synth_generator_compute_extended(synth_generator,
 					     audio_signal,
 					     note,
@@ -1156,6 +1157,7 @@ ags_apply_synth_launch(AgsTask *task)
 	  
 	pthread_mutex_lock(channel_mutex);
 
+	//FIXME:JK: not thread-safe
 	ags_synth_generator_compute_extended(AGS_INPUT(channel)->synth_generator,
 					     audio_signal,
 					     note,
@@ -1310,6 +1312,7 @@ ags_apply_synth_launch(AgsTask *task)
 	  
 	  pthread_mutex_lock(channel_mutex);
 	  
+	  //FIXME:JK: not thread-safe
 	  ags_synth_generator_compute_extended(synth_generator,
 					       audio_signal,
 					       note,
diff --git a/ags/audio/task/ags_crop_note.c b/ags/audio/task/ags_crop_note.c
index fbb3826..3b81bb3 100644
--- a/ags/audio/task/ags_crop_note.c
+++ b/ags/audio/task/ags_crop_note.c
@@ -21,6 +21,8 @@
 
 #include <ags/i18n.h>
 
+#include <math.h>
+
 void ags_crop_note_class_init(AgsCropNoteClass *crop_note);
 void ags_crop_note_connectable_interface_init(AgsConnectableInterface *connectable);
 void ags_crop_note_init(AgsCropNote *crop_note);
diff --git a/ags/audio/task/ags_init_channel.c b/ags/audio/task/ags_init_channel.c
index 3c4b7c7..077013c 100644
--- a/ags/audio/task/ags_init_channel.c
+++ b/ags/audio/task/ags_init_channel.c
@@ -476,7 +476,7 @@ ags_init_channel_launch(AgsTask *task)
 
     pthread_mutex_unlock(channel_mutex);
 
-    for(stage = 0; stage < 3; stage++){
+    for(stage = 0; stage < 4; stage++){
       current = channel;
       list = list_start;
       
@@ -641,7 +641,7 @@ ags_init_channel_launch(AgsTask *task)
   }else{
     AgsRecallID *recall_id;
 
-    for(stage = 0; stage < 3; stage++){
+    for(stage = 0; stage < 4; stage++){
       current = channel;
 
       /* get current mutex */
diff --git a/ags/audio/task/ags_move_note.c b/ags/audio/task/ags_move_note.c
index 1bf7820..453bb1b 100644
--- a/ags/audio/task/ags_move_note.c
+++ b/ags/audio/task/ags_move_note.c
@@ -21,6 +21,8 @@
 
 #include <ags/i18n.h>
 
+#include <math.h>
+
 void ags_move_note_class_init(AgsMoveNoteClass *move_note);
 void ags_move_note_connectable_interface_init(AgsConnectableInterface *connectable);
 void ags_move_note_init(AgsMoveNote *move_note);
diff --git a/ags/audio/task/recall/ags_apply_bpm.c b/ags/audio/task/recall/ags_apply_bpm.c
index fd7af8f..eb7418a 100644
--- a/ags/audio/task/recall/ags_apply_bpm.c
+++ b/ags/audio/task/recall/ags_apply_bpm.c
@@ -19,6 +19,8 @@
 
 #include <ags/audio/task/recall/ags_apply_bpm.h>
 
+#include <ags/libags.h>
+
 #include <ags/audio/ags_audio.h>
 #include <ags/audio/ags_channel.h>
 #include <ags/audio/ags_recall.h>
@@ -509,14 +511,14 @@ ags_apply_bpm_soundcard(AgsApplyBpm *apply_bpm, GObject *soundcard)
   pthread_mutex_unlock(application_mutex);
 
   /* set bpm and get audio */
-  pthread_mutex_lock(soundcard);
+  pthread_mutex_lock(soundcard_mutex);
 
   ags_soundcard_set_bpm(AGS_SOUNDCARD(soundcard), apply_bpm->bpm);
 
   list =
     list_start = g_list_copy(ags_soundcard_get_audio(AGS_SOUNDCARD(soundcard)));
 
-  pthread_mutex_unlock(soundcard);
+  pthread_mutex_unlock(soundcard_mutex);
 
   /* AgsAudio */
   while(list != NULL){
diff --git a/ags/audio/thread/ags_audio_loop.c b/ags/audio/thread/ags_audio_loop.c
index 22d48d7..b57f2b2 100644
--- a/ags/audio/thread/ags_audio_loop.c
+++ b/ags/audio/thread/ags_audio_loop.c
@@ -19,13 +19,7 @@
 
 #include <ags/audio/thread/ags_audio_loop.h>
 
-#include <ags/object/ags_config.h>
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_main_loop.h>
-#include <ags/object/ags_soundcard.h>
-
-#include <ags/thread/ags_mutex_manager.h>
-#include <ags/thread/ags_polling_thread.h>
+#include <ags/libags.h>
 
 #include <ags/audio/ags_audio.h>
 #include <ags/audio/ags_channel.h>
diff --git a/ags/audio/thread/ags_audio_thread.c b/ags/audio/thread/ags_audio_thread.c
index cf25975..bb3ff31 100644
--- a/ags/audio/thread/ags_audio_thread.c
+++ b/ags/audio/thread/ags_audio_thread.c
@@ -19,11 +19,7 @@
 
 #include <ags/audio/thread/ags_audio_thread.h>
 
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_config.h>
-#include <ags/object/ags_soundcard.h>
-
-#include <ags/thread/ags_mutex_manager.h>
+#include <ags/libags.h>
 
 #include <ags/audio/ags_audio.h>
 #include <ags/audio/ags_channel.h>
diff --git a/ags/audio/thread/ags_channel_thread.c b/ags/audio/thread/ags_channel_thread.c
index faa86ae..4d25666 100644
--- a/ags/audio/thread/ags_channel_thread.c
+++ b/ags/audio/thread/ags_channel_thread.c
@@ -19,11 +19,7 @@
 
 #include <ags/audio/thread/ags_channel_thread.h>
 
-#include <ags/object/ags_connectable.h>
-#include <ags/object/ags_config.h>
-#include <ags/object/ags_soundcard.h>
-
-#include <ags/thread/ags_mutex_manager.h>
+#include <ags/libags.h>
 
 #include <ags/audio/ags_channel.h>
 #include <ags/audio/ags_playback.h>
diff --git a/ags/gsequencer_main.c b/ags/gsequencer_main.c
index 721c3f8..72cd3cb 100644
--- a/ags/gsequencer_main.c
+++ b/ags/gsequencer_main.c
@@ -375,10 +375,11 @@ main(int argc, char **argv)
   ipatch_init();
 #endif
   
-#if 0
   g_log_set_fatal_mask("GLib-GObject", // "Gtk" , // 
   		       G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL); // G_LOG_LEVEL_WARNING
 
+#if 0
+
   g_log_set_fatal_mask("Gtk", // "Gtk" , // 
   		       G_LOG_LEVEL_CRITICAL); // G_LOG_LEVEL_WARNING
 #endif
diff --git a/ags/lib/ags_buffer_util.c b/ags/lib/ags_buffer_util.c
new file mode 100644
index 0000000..c62e434
--- /dev/null
+++ b/ags/lib/ags_buffer_util.c
@@ -0,0 +1,838 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2018 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/lib/ags_buffer_util.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * ags_buffer_util_s8_to_char_buffer:
+ * @buffer: the signed char buffer
+ * @buffer_length: the buffer length
+ * 
+ * Pack @buffer into an unsigned char buffer.
+ * 
+ * Returns: the unsigned char buffer
+ * 
+ * Since: 1.4.0
+ */
+unsigned char*
+ags_buffer_util_s8_to_char_buffer(signed char *buffer,
+				  guint buffer_length)
+{
+  unsigned char *cbuffer;
+
+  guint limit;
+  guint i;
+  
+  cbuffer = (unsigned char *) malloc(buffer_length * sizeof(unsigned char));
+
+  i = 0;
+  
+  if(buffer_length > 8){
+    limit = buffer_length - 8;
+
+    for(; i < limit; i += 8){
+      cbuffer[0] = (unsigned char) (0xff & buffer[0]);
+      cbuffer[1] = (unsigned char) (0xff & buffer[1]);
+      cbuffer[2] = (unsigned char) (0xff & buffer[2]);
+      cbuffer[3] = (unsigned char) (0xff & buffer[3]);
+      cbuffer[4] = (unsigned char) (0xff & buffer[4]);
+      cbuffer[5] = (unsigned char) (0xff & buffer[5]);
+      cbuffer[6] = (unsigned char) (0xff & buffer[6]);
+      cbuffer[7] = (unsigned char) (0xff & buffer[7]);
+
+      buffer += 8;
+      cbuffer += 8;
+    }
+  }
+
+  for(; i < buffer_length; i++){
+    cbuffer[0] = (unsigned char) (0xff & buffer[0]);
+
+    buffer++;
+    cbuffer++;
+  }
+
+  return(cbuffer);
+}
+
+/**
+ * ags_buffer_util_s16_to_char_buffer:
+ * @buffer: the signed short buffer
+ * @buffer_length: the buffer length
+ * 
+ * Pack @buffer into an unsigned char buffer.
+ * 
+ * Returns: the unsigned char buffer
+ * 
+ * Since: 1.4.0
+ */
+unsigned char*
+ags_buffer_util_s16_to_char_buffer(signed short *buffer,
+				   guint buffer_length)
+{
+  unsigned char *cbuffer;
+
+  guint limit;
+  guint i;
+  
+  cbuffer = (unsigned char *) malloc((2 * buffer_length) * sizeof(unsigned char));
+
+  i = 0;
+  
+  if(buffer_length > 8){
+    limit = buffer_length - 8;
+
+    for(; i < limit; i += 8){
+      cbuffer[0] = (unsigned char) (0xff & buffer[0]);
+      cbuffer[1] = (unsigned char) ((0xff00 & buffer[0]) >> 8);
+
+      cbuffer[2] = (unsigned char) (0xff & buffer[1]);
+      cbuffer[3] = (unsigned char) ((0xff00 & buffer[1]) >> 8);
+
+      cbuffer[4] = (unsigned char) (0xff & buffer[2]);
+      cbuffer[5] = (unsigned char) ((0xff00 & buffer[2]) >> 8);
+
+      cbuffer[6] = (unsigned char) (0xff & buffer[3]);
+      cbuffer[7] = (unsigned char) ((0xff00 & buffer[3]) >> 8);
+
+      cbuffer[8] = (unsigned char) (0xff & buffer[4]);
+      cbuffer[9] = (unsigned char) ((0xff00 & buffer[4]) >> 8);
+      
+      cbuffer[10] = (unsigned char) (0xff & buffer[5]);
+      cbuffer[11] = (unsigned char) ((0xff00 & buffer[5]) >> 8);
+
+      cbuffer[12] = (unsigned char) (0xff & buffer[6]);
+      cbuffer[13] = (unsigned char) ((0xff00 & buffer[6]) >> 8);
+
+      cbuffer[14] = (unsigned char) (0xff & buffer[7]);
+      cbuffer[15] = (unsigned char) ((0xff00 & buffer[7]) >> 8);
+      
+      buffer += 8;
+      cbuffer += (2 * 8);
+    }
+  }
+
+  for(; i < buffer_length; i++){
+    cbuffer[0] = (unsigned char) (0xff & buffer[0]);
+    cbuffer[1] = (unsigned char) ((0xff00 & buffer[0]) >> 8);
+
+    buffer++;
+    cbuffer += 2;
+  }
+
+  return(cbuffer);
+}
+
+/**
+ * ags_buffer_util_s24_to_char_buffer:
+ * @buffer: the signed long buffer
+ * @buffer_length: the buffer length
+ * 
+ * Pack @buffer into an unsigned char buffer.
+ * 
+ * Returns: the unsigned char buffer
+ * 
+ * Since: 1.4.0
+ */
+unsigned char*
+ags_buffer_util_s24_to_char_buffer(signed long *buffer,
+				   guint buffer_length)
+{
+  unsigned char *cbuffer;
+
+  guint limit;
+  guint i;
+  
+  cbuffer = (unsigned char *) malloc((3 * buffer_length) * sizeof(unsigned char));
+
+  i = 0;
+  
+  if(buffer_length > 8){
+    limit = buffer_length - 8;
+
+    for(; i < limit; i += 8){
+      cbuffer[0] = (unsigned char) (0xff & buffer[0]);
+      cbuffer[1] = (unsigned char) ((0xff00 & buffer[0]) >> 8);
+      cbuffer[2] = (unsigned char) ((0xff0000 & buffer[0]) >> 16);
+
+      cbuffer[3] = (unsigned char) (0xff & buffer[1]);
+      cbuffer[4] = (unsigned char) ((0xff00 & buffer[1]) >> 8);
+      cbuffer[5] = (unsigned char) ((0xff0000 & buffer[1]) >> 16);
+
+      cbuffer[6] = (unsigned char) (0xff & buffer[2]);
+      cbuffer[7] = (unsigned char) ((0xff00 & buffer[2]) >> 8);
+      cbuffer[8] = (unsigned char) ((0xff0000 & buffer[2]) >> 16);
+
+      cbuffer[9] = (unsigned char) (0xff & buffer[3]);
+      cbuffer[10] = (unsigned char) ((0xff00 & buffer[3]) >> 8);
+      cbuffer[11] = (unsigned char) ((0xff0000 & buffer[3]) >> 16);
+
+      cbuffer[12] = (unsigned char) (0xff & buffer[4]);
+      cbuffer[13] = (unsigned char) ((0xff00 & buffer[4]) >> 8);
+      cbuffer[14] = (unsigned char) ((0xff0000 & buffer[4]) >> 16);
+      
+      cbuffer[15] = (unsigned char) (0xff & buffer[5]);
+      cbuffer[16] = (unsigned char) ((0xff00 & buffer[5]) >> 8);
+      cbuffer[17] = (unsigned char) ((0xff0000 & buffer[5]) >> 16);
+
+      cbuffer[18] = (unsigned char) (0xff & buffer[6]);
+      cbuffer[19] = (unsigned char) ((0xff00 & buffer[6]) >> 8);
+      cbuffer[20] = (unsigned char) ((0xff0000 & buffer[6]) >> 16);
+
+      cbuffer[21] = (unsigned char) (0xff & buffer[7]);
+      cbuffer[22] = (unsigned char) ((0xff00 & buffer[7]) >> 8);
+      cbuffer[23] = (unsigned char) ((0xff0000 & buffer[7]) >> 16);
+      
+      buffer += 8;
+      cbuffer += (3 * 8);
+    }
+  }
+
+  for(; i < buffer_length; i++){
+    cbuffer[0] = (unsigned char) (0xff & buffer[0]);
+    cbuffer[1] = (unsigned char) ((0xff00 & buffer[0]) >> 8);
+    cbuffer[2] = (unsigned char) ((0xff0000 & buffer[0]) >> 16);
+
+    buffer++;
+    cbuffer += 3;
+  }
+
+  return(cbuffer);
+}
+
+/**
+ * ags_buffer_util_s32_to_char_buffer:
+ * @buffer: the signed long buffer
+ * @buffer_length: the buffer length
+ * 
+ * Pack @buffer into an unsigned char buffer.
+ * 
+ * Returns: the unsigned char buffer
+ * 
+ * Since: 1.4.0
+ */
+unsigned char*
+ags_buffer_util_s32_to_char_buffer(signed long *buffer,
+				   guint buffer_length)
+{
+  unsigned char *cbuffer;
+
+  guint limit;
+  guint i;
+  
+  cbuffer = (unsigned char *) malloc((4 * buffer_length) * sizeof(unsigned char));
+
+  i = 0;
+  
+  if(buffer_length > 8){
+    limit = buffer_length - 8;
+
+    for(; i < limit; i += 8){
+      cbuffer[0] = (unsigned char) (0xff & buffer[0]);
+      cbuffer[1] = (unsigned char) ((0xff00 & buffer[0]) >> 8);
+      cbuffer[2] = (unsigned char) ((0xff0000 & buffer[0]) >> 16);
+      cbuffer[3] = (unsigned char) ((0xff000000 & buffer[0]) >> 24);
+      
+      cbuffer[4] = (unsigned char) (0xff & buffer[1]);
+      cbuffer[5] = (unsigned char) ((0xff00 & buffer[1]) >> 8);
+      cbuffer[6] = (unsigned char) ((0xff0000 & buffer[1]) >> 16);
+      cbuffer[7] = (unsigned char) ((0xff000000 & buffer[1]) >> 24);
+
+      cbuffer[8] = (unsigned char) (0xff & buffer[2]);
+      cbuffer[9] = (unsigned char) ((0xff00 & buffer[2]) >> 8);
+      cbuffer[10] = (unsigned char) ((0xff0000 & buffer[2]) >> 16);
+      cbuffer[11] = (unsigned char) ((0xff000000 & buffer[2]) >> 24);
+
+      cbuffer[12] = (unsigned char) (0xff & buffer[3]);
+      cbuffer[13] = (unsigned char) ((0xff00 & buffer[3]) >> 8);
+      cbuffer[14] = (unsigned char) ((0xff0000 & buffer[3]) >> 16);
+      cbuffer[15] = (unsigned char) ((0xff000000 & buffer[3]) >> 24);
+
+      cbuffer[16] = (unsigned char) (0xff & buffer[4]);
+      cbuffer[17] = (unsigned char) ((0xff00 & buffer[4]) >> 8);
+      cbuffer[18] = (unsigned char) ((0xff0000 & buffer[4]) >> 16);
+      cbuffer[19] = (unsigned char) ((0xff000000 & buffer[4]) >> 24);
+
+      cbuffer[20] = (unsigned char) (0xff & buffer[5]);
+      cbuffer[21] = (unsigned char) ((0xff00 & buffer[5]) >> 8);
+      cbuffer[22] = (unsigned char) ((0xff0000 & buffer[5]) >> 16);
+      cbuffer[23] = (unsigned char) ((0xff000000 & buffer[5]) >> 24);
+
+      cbuffer[24] = (unsigned char) (0xff & buffer[6]);
+      cbuffer[25] = (unsigned char) ((0xff00 & buffer[6]) >> 8);
+      cbuffer[26] = (unsigned char) ((0xff0000 & buffer[6]) >> 16);
+      cbuffer[27] = (unsigned char) ((0xff000000 & buffer[6]) >> 24);
+
+      cbuffer[28] = (unsigned char) (0xff & buffer[7]);
+      cbuffer[29] = (unsigned char) ((0xff00 & buffer[7]) >> 8);
+      cbuffer[30] = (unsigned char) ((0xff0000 & buffer[7]) >> 16);
+      cbuffer[31] = (unsigned char) ((0xff000000 & buffer[7]) >> 24);
+      
+      buffer += 8;
+      cbuffer += (4 * 8);
+    }
+  }
+
+  for(; i < buffer_length; i++){
+    cbuffer[0] = (unsigned char) (0xff & buffer[0]);
+    cbuffer[1] = (unsigned char) ((0xff00 & buffer[0]) >> 8);
+    cbuffer[2] = (unsigned char) ((0xff0000 & buffer[0]) >> 16);
+    cbuffer[3] = (unsigned char) ((0xff000000 & buffer[0]) >> 24);
+
+    buffer++;
+    cbuffer += 4;
+  }
+
+  return(cbuffer);
+}
+
+/**
+ * ags_buffer_util_s64_to_char_buffer:
+ * @buffer: the signed long long buffer
+ * @buffer_length: the buffer length
+ * 
+ * Pack @buffer into an unsigned char buffer.
+ * 
+ * Returns: the unsigned char buffer
+ * 
+ * Since: 1.4.0
+ */
+unsigned char*
+ags_buffer_util_s64_to_char_buffer(signed long long *buffer,
+				   guint buffer_length)
+{
+  unsigned char *cbuffer;
+
+  guint limit;
+  guint i;
+  
+  cbuffer = (unsigned char *) malloc((8 * buffer_length) * sizeof(unsigned char));
+
+  i = 0;
+  
+  if(buffer_length > 8){
+    limit = buffer_length - 8;
+
+    for(; i < limit; i += 8){
+      cbuffer[0] = (unsigned char) (0xff & buffer[0]);
+      cbuffer[1] = (unsigned char) ((0xff00 & buffer[0]) >> 8);
+      cbuffer[2] = (unsigned char) ((0xff0000 & buffer[0]) >> 16);
+      cbuffer[3] = (unsigned char) ((0xff000000 & buffer[0]) >> 24);
+      cbuffer[4] = (unsigned char) ((0xff00000000 & buffer[0]) >> 32);
+      cbuffer[5] = (unsigned char) ((0xff0000000000 & buffer[0]) >> 40);
+      cbuffer[6] = (unsigned char) ((0xff000000000000 & buffer[0]) >> 48);
+      cbuffer[7] = (unsigned char) ((0xff00000000000000 & buffer[0]) >> 56);
+
+      cbuffer[8] = (unsigned char) (0xff & buffer[1]);
+      cbuffer[9] = (unsigned char) ((0xff00 & buffer[1]) >> 8);
+      cbuffer[10] = (unsigned char) ((0xff0000 & buffer[1]) >> 16);
+      cbuffer[11] = (unsigned char) ((0xff000000 & buffer[1]) >> 24);
+      cbuffer[12] = (unsigned char) ((0xff00000000 & buffer[1]) >> 32);
+      cbuffer[13] = (unsigned char) ((0xff0000000000 & buffer[1]) >> 40);
+      cbuffer[14] = (unsigned char) ((0xff000000000000 & buffer[1]) >> 48);
+      cbuffer[15] = (unsigned char) ((0xff00000000000000 & buffer[1]) >> 56);
+
+      cbuffer[16] = (unsigned char) (0xff & buffer[2]);
+      cbuffer[17] = (unsigned char) ((0xff00 & buffer[2]) >> 8);
+      cbuffer[18] = (unsigned char) ((0xff0000 & buffer[2]) >> 16);
+      cbuffer[19] = (unsigned char) ((0xff000000 & buffer[2]) >> 24);
+      cbuffer[20] = (unsigned char) ((0xff00000000 & buffer[2]) >> 32);
+      cbuffer[21] = (unsigned char) ((0xff0000000000 & buffer[2]) >> 40);
+      cbuffer[22] = (unsigned char) ((0xff000000000000 & buffer[2]) >> 48);
+      cbuffer[23] = (unsigned char) ((0xff00000000000000 & buffer[2]) >> 56);
+
+      cbuffer[24] = (unsigned char) (0xff & buffer[3]);
+      cbuffer[25] = (unsigned char) ((0xff00 & buffer[3]) >> 8);
+      cbuffer[26] = (unsigned char) ((0xff0000 & buffer[3]) >> 16);
+      cbuffer[27] = (unsigned char) ((0xff000000 & buffer[3]) >> 24);
+      cbuffer[28] = (unsigned char) ((0xff00000000 & buffer[3]) >> 32);
+      cbuffer[29] = (unsigned char) ((0xff0000000000 & buffer[3]) >> 40);
+      cbuffer[30] = (unsigned char) ((0xff000000000000 & buffer[3]) >> 48);
+      cbuffer[31] = (unsigned char) ((0xff00000000000000 & buffer[3]) >> 56);
+
+      cbuffer[32] = (unsigned char) (0xff & buffer[4]);
+      cbuffer[33] = (unsigned char) ((0xff00 & buffer[4]) >> 8);
+      cbuffer[34] = (unsigned char) ((0xff0000 & buffer[4]) >> 16);
+      cbuffer[35] = (unsigned char) ((0xff000000 & buffer[4]) >> 24);
+      cbuffer[36] = (unsigned char) ((0xff00000000 & buffer[4]) >> 32);
+      cbuffer[37] = (unsigned char) ((0xff0000000000 & buffer[4]) >> 40);
+      cbuffer[38] = (unsigned char) ((0xff000000000000 & buffer[4]) >> 48);
+      cbuffer[39] = (unsigned char) ((0xff00000000000000 & buffer[4]) >> 56);
+      
+      cbuffer[40] = (unsigned char) (0xff & buffer[5]);
+      cbuffer[41] = (unsigned char) ((0xff00 & buffer[5]) >> 8);
+      cbuffer[42] = (unsigned char) ((0xff0000 & buffer[5]) >> 16);
+      cbuffer[43] = (unsigned char) ((0xff000000 & buffer[5]) >> 24);
+      cbuffer[44] = (unsigned char) ((0xff00000000 & buffer[5]) >> 32);
+      cbuffer[45] = (unsigned char) ((0xff0000000000 & buffer[5]) >> 40);
+      cbuffer[46] = (unsigned char) ((0xff000000000000 & buffer[5]) >> 48);
+      cbuffer[47] = (unsigned char) ((0xff00000000000000 & buffer[5]) >> 56);
+
+      cbuffer[48] = (unsigned char) (0xff & buffer[6]);
+      cbuffer[49] = (unsigned char) ((0xff00 & buffer[6]) >> 8);
+      cbuffer[50] = (unsigned char) ((0xff0000 & buffer[6]) >> 16);
+      cbuffer[51] = (unsigned char) ((0xff000000 & buffer[6]) >> 24);
+      cbuffer[52] = (unsigned char) ((0xff00000000 & buffer[6]) >> 32);
+      cbuffer[53] = (unsigned char) ((0xff0000000000 & buffer[6]) >> 40);
+      cbuffer[54] = (unsigned char) ((0xff000000000000 & buffer[6]) >> 48);
+      cbuffer[55] = (unsigned char) ((0xff00000000000000 & buffer[6]) >> 56);
+
+      cbuffer[56] = (unsigned char) (0xff & buffer[7]);
+      cbuffer[57] = (unsigned char) ((0xff00 & buffer[7]) >> 8);
+      cbuffer[58] = (unsigned char) ((0xff0000 & buffer[7]) >> 16);
+      cbuffer[59] = (unsigned char) ((0xff000000 & buffer[7]) >> 24);
+      cbuffer[60] = (unsigned char) ((0xff00000000 & buffer[7]) >> 32);
+      cbuffer[61] = (unsigned char) ((0xff0000000000 & buffer[7]) >> 40);
+      cbuffer[62] = (unsigned char) ((0xff000000000000 & buffer[7]) >> 48);
+      cbuffer[63] = (unsigned char) ((0xff00000000000000 & buffer[7]) >> 56);
+
+      buffer += 8;
+      cbuffer += (8 * 8);
+    }
+  }
+
+  for(; i < buffer_length; i++){
+    cbuffer[0] = (unsigned char) (0xff & buffer[0]);
+    cbuffer[1] = (unsigned char) ((0xff00 & buffer[0]) >> 8);
+    cbuffer[2] = (unsigned char) ((0xff0000 & buffer[0]) >> 16);
+    cbuffer[3] = (unsigned char) ((0xff000000 & buffer[0]) >> 24);
+    cbuffer[4] = (unsigned char) ((0xff00000000 & buffer[0]) >> 32);
+    cbuffer[5] = (unsigned char) ((0xff0000000000 & buffer[0]) >> 40);
+    cbuffer[6] = (unsigned char) ((0xff000000000000 & buffer[0]) >> 48);
+    cbuffer[7] = (unsigned char) ((0xff00000000000000 & buffer[0]) >> 56);
+
+    buffer++;
+    cbuffer += 8;
+  }
+
+  return(cbuffer);
+}
+
+/**
+ * ags_buffer_util_char_buffer_to_s8:
+ * @cbuffer: the unsigned char buffer
+ * @buffer_size: the buffer size
+ *
+ * Unpack @cbuffer to a signed char buffer
+ *
+ * Returns: the signed char buffer
+ * 
+ * Since: 1.4.0
+ */
+signed char*
+ags_buffer_util_char_buffer_to_s8(unsigned char *cbuffer,
+				  guint buffer_size)
+{
+  signed char *buffer;
+
+  guint limit;
+  guint i;
+
+  buffer = (signed char *) malloc(buffer_size * sizeof(signed char));
+  memset(buffer, 0, buffer_size * sizeof(signed char));
+  
+  i = 0;
+  
+  if(buffer_size > 8){
+    limit = buffer_size - 8;
+
+    for(; i < limit; i += 8){
+      buffer[0] |= (0xff & cbuffer[0]);
+      buffer[1] |= (0xff & cbuffer[1]);
+      buffer[2] |= (0xff & cbuffer[2]);
+      buffer[3] |= (0xff & cbuffer[3]);
+      buffer[4] |= (0xff & cbuffer[4]);
+      buffer[5] |= (0xff & cbuffer[5]);
+      buffer[6] |= (0xff & cbuffer[6]);
+      buffer[7] |= (0xff & cbuffer[7]);
+      
+      buffer += 8;
+      cbuffer += 8;
+    }
+  }
+
+  for(; i < buffer_size; i++){
+    buffer[0] |= (0xff & cbuffer[0]);
+      
+    buffer++;
+    cbuffer++;
+  }
+
+  return(buffer);
+}
+
+/**
+ * ags_buffer_util_char_buffer_to_s16:
+ * @cbuffer: the unsigned char buffer
+ * @buffer_size: the buffer size
+ *
+ * Unpack @cbuffer to a signed short buffer
+ *
+ * Returns: the signed short buffer
+ * 
+ * Since: 1.4.0
+ */
+signed short*
+ags_buffer_util_char_buffer_to_s16(unsigned char *cbuffer,
+				   guint buffer_size)
+{
+  signed short *buffer;
+
+  guint limit;
+  guint i;
+
+  buffer = (signed short *) malloc((buffer_size / 2) * sizeof(signed short));
+  memset(buffer, 0, (buffer_size / 2) * sizeof(signed short));
+  
+  i = 0;
+  
+  if(buffer_size / 2 > 8){
+    limit = (buffer_size / 2) - 8;
+
+    for(; i < limit; i += 8){
+      buffer[0] |= (0xff & cbuffer[0]);
+      buffer[0] |= ((0xff & cbuffer[1]) << 8);
+      
+      buffer[1] |= (0xff & cbuffer[2]);
+      buffer[1] |= ((0xff & cbuffer[3]) << 8);
+
+      buffer[2] |= (0xff & cbuffer[4]);
+      buffer[2] |= ((0xff & cbuffer[5]) << 8);
+
+      buffer[3] |= (0xff & cbuffer[6]);
+      buffer[3] |= ((0xff & cbuffer[7]) << 8);
+      
+      buffer[4] |= (0xff & cbuffer[8]);
+      buffer[4] |= ((0xff & cbuffer[9]) << 8);
+      
+      buffer[5] |= (0xff & cbuffer[10]);
+      buffer[5] |= ((0xff & cbuffer[11]) << 8);
+
+      buffer[6] |= (0xff & cbuffer[12]);
+      buffer[6] |= ((0xff & cbuffer[13]) << 8);
+
+      buffer[7] |= (0xff & cbuffer[14]);
+      buffer[7] |= ((0xff & cbuffer[15]) << 8);
+
+      buffer += 8;
+      cbuffer += (2 * 8);
+    }
+  }
+
+  for(; i < buffer_size; i += 2){
+    buffer[0] |= (0xff & cbuffer[0]);
+    buffer[0] |= ((0xff & cbuffer[1]) << 8);
+      
+    buffer++;
+    cbuffer += 2;
+  }
+
+  return(buffer);
+}
+
+/**
+ * ags_buffer_util_char_buffer_to_s24:
+ * @cbuffer: the unsigned char buffer
+ * @buffer_size: the buffer size
+ *
+ * Unpack @cbuffer to a signed long buffer
+ *
+ * Returns: the signed long buffer
+ * 
+ * Since: 1.4.0
+ */
+signed long*
+ags_buffer_util_char_buffer_to_s24(unsigned char *cbuffer,
+				   guint buffer_size)
+{
+  signed long *buffer;
+
+  guint limit;
+  guint i;
+
+  buffer = (signed long *) malloc((buffer_size / 3) * sizeof(signed long));
+  memset(buffer, 0, (buffer_size / 3) * sizeof(signed long));
+  
+  i = 0;
+  
+  if(buffer_size / 3 > 8){
+    limit = (buffer_size / 3) - 8;
+
+    for(; i < limit; i += 8){
+      buffer[0] |= (0xff & cbuffer[0]);
+      buffer[0] |= ((0xff & cbuffer[1]) << 8);
+      buffer[0] |= ((0xff & cbuffer[2]) << 16);
+      
+      buffer[1] |= (0xff & cbuffer[3]);
+      buffer[1] |= ((0xff & cbuffer[4]) << 8);
+      buffer[1] |= ((0xff & cbuffer[5]) << 16);
+
+      buffer[2] |= (0xff & cbuffer[6]);
+      buffer[2] |= ((0xff & cbuffer[7]) << 8);
+      buffer[2] |= ((0xff & cbuffer[8]) << 16);
+      
+      buffer[3] |= (0xff & cbuffer[9]);
+      buffer[3] |= ((0xff & cbuffer[10]) << 8);
+      buffer[3] |= ((0xff & cbuffer[11]) << 16);
+      
+      buffer[4] |= (0xff & cbuffer[12]);
+      buffer[4] |= ((0xff & cbuffer[13]) << 8);
+      buffer[4] |= ((0xff & cbuffer[14]) << 16);
+      
+      buffer[5] |= (0xff & cbuffer[15]);
+      buffer[5] |= ((0xff & cbuffer[16]) << 8);
+      buffer[5] |= ((0xff & cbuffer[17]) << 16);
+      
+      buffer[6] |= (0xff & cbuffer[18]);
+      buffer[6] |= ((0xff & cbuffer[19]) << 8);
+      buffer[6] |= ((0xff & cbuffer[20]) << 16);
+      
+      buffer[7] |= (0xff & cbuffer[21]);
+      buffer[7] |= ((0xff & cbuffer[22]) << 8);
+      buffer[7] |= ((0xff & cbuffer[23]) << 16);
+      
+      buffer += 8;
+      cbuffer += (3 * 8);
+    }
+  }
+
+  for(; i < buffer_size; i += 3){
+    buffer[0] |= (0xff & cbuffer[0]);
+    buffer[0] |= ((0xff & cbuffer[1]) << 8);
+    buffer[0] |= ((0xff & cbuffer[2]) << 16);
+      
+    buffer++;
+    cbuffer += 3;
+  }
+
+  return(buffer);
+}
+
+/**
+ * ags_buffer_util_char_buffer_to_s32:
+ * @cbuffer: the unsigned char buffer
+ * @buffer_size: the buffer size
+ *
+ * Unpack @cbuffer to a signed long buffer
+ *
+ * Returns: the signed long buffer
+ * 
+ * Since: 1.4.0
+ */
+signed long*
+ags_buffer_util_char_buffer_to_s32(unsigned char *cbuffer,
+				   guint buffer_size)
+{
+  signed long *buffer;
+
+  guint limit;
+  guint i;
+
+  buffer = (signed long *) malloc((buffer_size / 4) * sizeof(signed long));
+  memset(buffer, 0, (buffer_size / 4) * sizeof(signed long));
+  
+  i = 0;
+  
+  if((buffer_size / 4) > 8){
+    limit = (buffer_size / 4) - 8;
+
+    for(; i < limit; i += 8){
+      buffer[0] |= (0xff & cbuffer[0]);
+      buffer[0] |= ((0xff & cbuffer[1]) << 8);
+      buffer[0] |= ((0xff & cbuffer[2]) << 16);
+      buffer[0] |= ((0xff & cbuffer[3]) << 24);
+      
+      buffer[1] |= (0xff & cbuffer[4]);
+      buffer[1] |= ((0xff & cbuffer[5]) << 8);
+      buffer[1] |= ((0xff & cbuffer[6]) << 16);
+      buffer[1] |= ((0xff & cbuffer[7]) << 24);
+      
+      buffer[2] |= (0xff & cbuffer[8]);
+      buffer[2] |= ((0xff & cbuffer[9]) << 8);
+      buffer[2] |= ((0xff & cbuffer[10]) << 16);
+      buffer[2] |= ((0xff & cbuffer[11]) << 24);
+
+      buffer[3] |= (0xff & cbuffer[12]);
+      buffer[3] |= ((0xff & cbuffer[13]) << 8);
+      buffer[3] |= ((0xff & cbuffer[14]) << 16);
+      buffer[3] |= ((0xff & cbuffer[15]) << 24);
+
+      buffer[4] |= (0xff & cbuffer[16]);
+      buffer[4] |= ((0xff & cbuffer[17]) << 8);
+      buffer[4] |= ((0xff & cbuffer[18]) << 16);
+      buffer[4] |= ((0xff & cbuffer[19]) << 24);
+
+      buffer[5] |= (0xff & cbuffer[20]);
+      buffer[5] |= ((0xff & cbuffer[21]) << 8);
+      buffer[5] |= ((0xff & cbuffer[22]) << 16);
+      buffer[5] |= ((0xff & cbuffer[23]) << 24);
+
+      buffer[6] |= (0xff & cbuffer[24]);
+      buffer[6] |= ((0xff & cbuffer[25]) << 8);
+      buffer[6] |= ((0xff & cbuffer[26]) << 16);
+      buffer[6] |= ((0xff & cbuffer[27]) << 24);
+
+      buffer[7] |= (0xff & cbuffer[28]);
+      buffer[7] |= ((0xff & cbuffer[29]) << 8);
+      buffer[7] |= ((0xff & cbuffer[30]) << 16);
+      buffer[7] |= ((0xff & cbuffer[31]) << 24);
+
+      buffer += 8;
+      cbuffer += (4 * 8);
+    }
+  }
+
+  for(; i < buffer_size; i += 4){
+    buffer[0] |= (0xff & cbuffer[0]);
+    buffer[0] |= ((0xff & cbuffer[1]) << 8);
+    buffer[0] |= ((0xff & cbuffer[2]) << 16);
+    buffer[0] |= ((0xff & cbuffer[3]) << 24);
+      
+    buffer++;
+    cbuffer += 4;
+  }
+
+  return(buffer);
+}
+
+/**
+ * ags_buffer_util_char_buffer_to_s64:
+ * @cbuffer: the unsigned char buffer
+ * @buffer_size: the buffer size
+ *
+ * Unpack @cbuffer to a signed long long buffer
+ *
+ * Returns: the signed long long buffer
+ * 
+ * Since: 1.4.0
+ */
+signed long long*
+ags_buffer_util_char_buffer_to_s64(unsigned char *cbuffer,
+				   guint buffer_size)
+{
+  signed long long *buffer;
+
+  guint limit;
+  guint i;
+
+  buffer = (signed long long *) malloc((buffer_size / 8) * sizeof(signed long long));
+  memset(buffer, 0, (buffer_size / 8) * sizeof(signed long long));
+  
+  i = 0;
+  
+  if(buffer_size / 8 > 8){
+    limit = (buffer_size / 8) - 8;
+
+    for(; i < limit; i += 8){
+      buffer[0] |= (0xff & cbuffer[0]);
+      buffer[0] |= ((0xff & cbuffer[1]) << 8);
+      buffer[0] |= ((0xff & cbuffer[2]) << 16);
+      buffer[0] |= ((0xff & cbuffer[3]) << 24);
+      buffer[0] |= ((0xff & cbuffer[4]) << 32);
+      buffer[0] |= ((0xff & cbuffer[5]) << 40);
+      buffer[0] |= ((0xff & cbuffer[6]) << 48);
+      buffer[0] |= ((0xff & cbuffer[7]) << 56);
+      
+      buffer[1] |= (0xff & cbuffer[8]);
+      buffer[1] |= ((0xff & cbuffer[9]) << 8);
+      buffer[1] |= ((0xff & cbuffer[10]) << 16);
+      buffer[1] |= ((0xff & cbuffer[11]) << 24);
+      buffer[1] |= ((0xff & cbuffer[12]) << 32);
+      buffer[1] |= ((0xff & cbuffer[13]) << 40);
+      buffer[1] |= ((0xff & cbuffer[14]) << 48);
+      buffer[1] |= ((0xff & cbuffer[15]) << 56);
+      
+      buffer[2] |= (0xff & cbuffer[16]);
+      buffer[2] |= ((0xff & cbuffer[17]) << 8);
+      buffer[2] |= ((0xff & cbuffer[18]) << 16);
+      buffer[2] |= ((0xff & cbuffer[19]) << 24);
+      buffer[2] |= ((0xff & cbuffer[20]) << 32);
+      buffer[2] |= ((0xff & cbuffer[21]) << 40);
+      buffer[2] |= ((0xff & cbuffer[22]) << 48);
+      buffer[2] |= ((0xff & cbuffer[23]) << 56);
+      
+      buffer[3] |= (0xff & cbuffer[24]);
+      buffer[3] |= ((0xff & cbuffer[25]) << 8);
+      buffer[3] |= ((0xff & cbuffer[26]) << 16);
+      buffer[3] |= ((0xff & cbuffer[27]) << 24);
+      buffer[3] |= ((0xff & cbuffer[28]) << 32);
+      buffer[3] |= ((0xff & cbuffer[29]) << 40);
+      buffer[3] |= ((0xff & cbuffer[30]) << 48);
+      buffer[3] |= ((0xff & cbuffer[31]) << 56);
+      
+      buffer[4] |= (0xff & cbuffer[32]);
+      buffer[4] |= ((0xff & cbuffer[33]) << 8);
+      buffer[4] |= ((0xff & cbuffer[34]) << 16);
+      buffer[4] |= ((0xff & cbuffer[35]) << 24);
+      buffer[4] |= ((0xff & cbuffer[36]) << 32);
+      buffer[4] |= ((0xff & cbuffer[37]) << 40);
+      buffer[4] |= ((0xff & cbuffer[38]) << 48);
+      buffer[4] |= ((0xff & cbuffer[39]) << 56);
+      
+      buffer[5] |= (0xff & cbuffer[40]);
+      buffer[5] |= ((0xff & cbuffer[41]) << 8);
+      buffer[5] |= ((0xff & cbuffer[42]) << 16);
+      buffer[5] |= ((0xff & cbuffer[43]) << 24);
+      buffer[5] |= ((0xff & cbuffer[44]) << 32);
+      buffer[5] |= ((0xff & cbuffer[45]) << 40);
+      buffer[5] |= ((0xff & cbuffer[46]) << 48);
+      buffer[5] |= ((0xff & cbuffer[47]) << 56);
+      
+      buffer[6] |= (0xff & cbuffer[48]);
+      buffer[6] |= ((0xff & cbuffer[49]) << 8);
+      buffer[6] |= ((0xff & cbuffer[50]) << 16);
+      buffer[6] |= ((0xff & cbuffer[51]) << 24);
+      buffer[6] |= ((0xff & cbuffer[52]) << 32);
+      buffer[6] |= ((0xff & cbuffer[53]) << 40);
+      buffer[6] |= ((0xff & cbuffer[54]) << 48);
+      buffer[6] |= ((0xff & cbuffer[55]) << 56);
+      
+      buffer[7] |= (0xff & cbuffer[56]);
+      buffer[7] |= ((0xff & cbuffer[57]) << 8);
+      buffer[7] |= ((0xff & cbuffer[58]) << 16);
+      buffer[7] |= ((0xff & cbuffer[59]) << 24);
+      buffer[7] |= ((0xff & cbuffer[60]) << 32);
+      buffer[7] |= ((0xff & cbuffer[61]) << 40);
+      buffer[7] |= ((0xff & cbuffer[62]) << 48);
+      buffer[7] |= ((0xff & cbuffer[63]) << 56);
+      
+      buffer += 8;
+      cbuffer += (8 * 8);
+    }
+  }
+
+  for(; i < buffer_size; i += 8){
+    buffer[0] |= (0xff & cbuffer[0]);
+    buffer[0] |= ((0xff & cbuffer[1]) << 8);
+    buffer[0] |= ((0xff & cbuffer[2]) << 16);
+    buffer[0] |= ((0xff & cbuffer[3]) << 24);
+    buffer[0] |= ((0xff & cbuffer[4]) << 32);
+    buffer[0] |= ((0xff & cbuffer[5]) << 40);
+    buffer[0] |= ((0xff & cbuffer[6]) << 48);
+    buffer[0] |= ((0xff & cbuffer[7]) << 56);
+      
+    buffer++;
+    cbuffer += 8;
+  }
+
+  return(buffer);
+}
diff --git a/ags/lib/ags_buffer_util.h b/ags/lib/ags_buffer_util.h
new file mode 100644
index 0000000..9c7b8f9
--- /dev/null
+++ b/ags/lib/ags_buffer_util.h
@@ -0,0 +1,48 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2018 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_BUFFER_UTIL_H__
+#define __AGS_BUFFER_UTIL_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+unsigned char* ags_buffer_util_s8_to_char_buffer(signed char *buffer,
+						 guint buffer_length);
+unsigned char* ags_buffer_util_s16_to_char_buffer(signed short *buffer,
+						  guint buffer_length);
+unsigned char* ags_buffer_util_s24_to_char_buffer(signed long *buffer,
+						  guint buffer_length);
+unsigned char* ags_buffer_util_s32_to_char_buffer(signed long *buffer,
+						  guint buffer_length);
+unsigned char* ags_buffer_util_s64_to_char_buffer(signed long long *buffer,
+						  guint buffer_length);
+
+signed char* ags_buffer_util_char_buffer_to_s8(unsigned char *cbuffer,
+					       guint buffer_size);
+signed short* ags_buffer_util_char_buffer_to_s16(unsigned char *cbuffer,
+						 guint buffer_size);
+signed long* ags_buffer_util_char_buffer_to_s24(unsigned char *cbuffer,
+						guint buffer_size);
+signed long* ags_buffer_util_char_buffer_to_s32(unsigned char *cbuffer,
+						guint buffer_size);
+signed long long* ags_buffer_util_char_buffer_to_s64(unsigned char *cbuffer,
+						     guint buffer_size);
+
+#endif /*__AGS_BUFFER_UTIL_H__*/
diff --git a/ags/libags-audio.h b/ags/libags-audio.h
index 34a5cad..561c912 100644
--- a/ags/libags-audio.h
+++ b/ags/libags-audio.h
@@ -51,6 +51,7 @@
 #include <ags/audio/ags_audio_connection.h>
 #include <ags/audio/ags_audio_signal.h>
 #include <ags/audio/ags_automation.h>
+#include <ags/audio/ags_buffer.h>
 #include <ags/audio/ags_channel.h>
 #include <ags/audio/ags_channel_iter.h>
 #include <ags/audio/ags_devout.h>
@@ -92,6 +93,7 @@
 #include <ags/audio/ags_sound_provider.h>
 #include <ags/audio/ags_synth_generator.h>
 #include <ags/audio/ags_synth_util.h>
+#include <ags/audio/ags_wave.h>
 
 /* audio thread */
 #include <ags/audio/thread/ags_audio_loop.h>
diff --git a/ags/libags-gui.h b/ags/libags-gui.h
index a944cb5..9222265 100644
--- a/ags/libags-gui.h
+++ b/ags/libags-gui.h
@@ -25,10 +25,13 @@
 #include <ags/widget/ags_dial.h>
 #include <ags/widget/ags_expander_set.h>
 #include <ags/widget/ags_hindicator.h>
+#include <ags/widget/ags_hlevel_box.h>
 #include <ags/widget/ags_hscale_box.h>
 #include <ags/widget/ags_indicator.h>
 #include <ags/widget/ags_led.h>
 #include <ags/widget/ags_led_array.h>
+#include <ags/widget/ags_level.h>
+#include <ags/widget/ags_level_box.h>
 #include <ags/widget/ags_hled_array.h>
 #include <ags/widget/ags_vled_array.h>
 #include <ags/widget/ags_notebook.h>
@@ -37,9 +40,11 @@
 #include <ags/widget/ags_scale.h>
 #include <ags/widget/ags_scale_box.h>
 #include <ags/widget/ags_scrolled_piano.h>
+#include <ags/widget/ags_scrolled_level_box.h>
 #include <ags/widget/ags_scrolled_scale_box.h>
 #include <ags/widget/ags_ruler.h>
 #include <ags/widget/ags_vindicator.h>
+#include <ags/widget/ags_vlevel_box.h>
 #include <ags/widget/ags_vscale_box.h>
 #include <ags/widget/ags_widget_marshal.h>
 
diff --git a/ags/libags.h b/ags/libags.h
index 8261b6f..0b53b72 100644
--- a/ags/libags.h
+++ b/ags/libags.h
@@ -25,6 +25,7 @@
 #include <ags/util/ags_id_generator.h>
 
 /* library */
+#include <ags/lib/ags_buffer_util.h>
 #include <ags/lib/ags_complex.h>
 #include <ags/lib/ags_conversion.h>
 #include <ags/lib/ags_endian.h>
diff --git a/ags/object/ags_config.c b/ags/object/ags_config.c
index b1dee0e..2565e73 100644
--- a/ags/object/ags_config.c
+++ b/ags/object/ags_config.c
@@ -423,9 +423,10 @@ ags_config_real_load_defaults(AgsConfig *config)
   ags_config_set_value(config, AGS_CONFIG_GENERIC, "engine-mode", "performance");
 
   ags_config_set_value(config, AGS_CONFIG_THREAD, "model", "super-threaded");
-  ags_config_set_value(config, AGS_CONFIG_THREAD, "super-threaded-scope", "channel");
+  ags_config_set_value(config, AGS_CONFIG_THREAD, "super-threaded-scope", "audio");
   ags_config_set_value(config, AGS_CONFIG_THREAD, "lock-global", "ags-thread");
   ags_config_set_value(config, AGS_CONFIG_THREAD, "lock-parent", "ags-recycling-thread");
+  ags_config_set_value(config, AGS_CONFIG_THREAD, "max-precision", "125");
 
 #ifdef AGS_WITH_CORE_AUDIO
   ags_config_set_value(config, AGS_CONFIG_SOUNDCARD_0, "backend", "core-audio");
diff --git a/ags/test/X/ags_functional_test_util.c b/ags/test/X/ags_functional_test_util.c
index 5111bd0..93dd3d4 100644
--- a/ags/test/X/ags_functional_test_util.c
+++ b/ags/test/X/ags_functional_test_util.c
@@ -32,8 +32,8 @@
 
 #include <pthread.h>
 
-#define AGS_FUNCTIONAL_TEST_UTIL_REACTION_TIME (125000)
-#define AGS_FUNCTIONAL_TEST_UTIL_REACTION_TIME_LONG (500000)
+#define AGS_FUNCTIONAL_TEST_UTIL_REACTION_TIME (1000000)
+#define AGS_FUNCTIONAL_TEST_UTIL_REACTION_TIME_LONG (2000000)
 
 gboolean ags_functional_test_util_driver_prepare(GSource *source,
 						 gint *timeout_);
@@ -66,7 +66,7 @@ struct _AddTest{
 };
 
 struct timespec ags_functional_test_util_default_timeout = {
-  20,
+  59,
   0,
 };
 
diff --git a/ags/widget/ags_hlevel_box.c b/ags/widget/ags_hlevel_box.c
new file mode 100644
index 0000000..1804f89
--- /dev/null
+++ b/ags/widget/ags_hlevel_box.c
@@ -0,0 +1,93 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2017 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/widget/ags_hlevel_box.h>
+
+void ags_hlevel_box_class_init(AgsHLevelBoxClass *hlevel_box);
+void ags_hlevel_box_init(AgsHLevelBox *hlevel_box);
+
+/**
+ * SECTION:ags_hlevel_box
+ * @short_description: horizontal box widget
+ * @title: AgsHLevelBox
+ * @section_id:
+ * @include: ags/widget/ags_hlevel_box.h
+ *
+ * The #AgsHLevelBox is an horizontal box widget containing #AgsLevel.
+ */
+
+static gpointer ags_hlevel_box_parent_class = NULL;
+
+GType
+ags_hlevel_box_get_type(void)
+{
+  static GType ags_type_hlevel_box = 0;
+
+  if(!ags_type_hlevel_box){
+    static const GTypeInfo ags_hlevel_box_info = {
+      sizeof (AgsHLevelBoxClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      (GClassInitFunc) ags_hlevel_box_class_init,
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof (AgsHLevelBox),
+      0,    /* n_preallocs */
+      (GInstanceInitFunc) ags_hlevel_box_init,
+    };
+
+    ags_type_hlevel_box = g_type_register_static(AGS_TYPE_LEVEL_BOX,
+						 "AgsHLevelBox", &ags_hlevel_box_info,
+						 0);
+  }
+  
+  return(ags_type_hlevel_box);
+}
+
+void
+ags_hlevel_box_class_init(AgsHLevelBoxClass *hlevel_box)
+{
+}
+
+void
+ags_hlevel_box_init(AgsHLevelBox *hlevel_box)
+{
+  gtk_orientable_set_orientation(GTK_ORIENTABLE(hlevel_box),
+				 GTK_ORIENTATION_HORIZONTAL);
+}
+
+/**
+ * ags_hlevel_box_new:
+ * 
+ * Create a new instance of #AgsHLevelBox.
+ * 
+ * Returns: the new #AgsHLevelBox instance
+ * 
+ * Since: 1.4.0
+ */
+AgsHLevelBox*
+ags_hlevel_box_new()
+{
+  AgsHLevelBox *hlevel_box;
+
+  hlevel_box = (AgsHLevelBox *) g_object_new(AGS_TYPE_HLEVEL_BOX,
+					     NULL);
+  
+  return(hlevel_box);
+}
diff --git a/ags/widget/ags_hlevel_box.h b/ags/widget/ags_hlevel_box.h
new file mode 100644
index 0000000..95561fc
--- /dev/null
+++ b/ags/widget/ags_hlevel_box.h
@@ -0,0 +1,54 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2017 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_HLEVEL_BOX_H__
+#define __AGS_HLEVEL_BOX_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+#include <ags/widget/ags_level_box.h>
+
+#define AGS_TYPE_HLEVEL_BOX                (ags_hlevel_box_get_type())
+#define AGS_HLEVEL_BOX(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_HLEVEL_BOX, AgsHLevelBox))
+#define AGS_HLEVEL_BOX_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_HLEVEL_BOX, AgsHLevelBoxClass))
+#define AGS_IS_HLEVEL_BOX(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AGS_TYPE_HLEVEL_BOX))
+#define AGS_IS_HLEVEL_BOX_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_HLEVEL_BOX))
+#define AGS_HLEVEL_BOX_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS (obj, AGS_TYPE_HLEVEL_BOX, AgsHLevelBoxClass))
+
+typedef struct _AgsHLevelBox AgsHLevelBox;
+typedef struct _AgsHLevelBoxClass AgsHLevelBoxClass;
+
+struct _AgsHLevelBox
+{
+  AgsLevelBox level_box;
+};
+
+struct _AgsHLevelBoxClass
+{
+  AgsLevelBoxClass level_box;
+};
+
+GType ags_hlevel_box_get_type(void);
+
+AgsHLevelBox* ags_hlevel_box_new();
+
+#endif /*__AGS_HLEVEL_BOX_H__*/
diff --git a/ags/widget/ags_level.c b/ags/widget/ags_level.c
new file mode 100644
index 0000000..4393140
--- /dev/null
+++ b/ags/widget/ags_level.c
@@ -0,0 +1,1215 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2017 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/widget/ags_level.h>
+
+#include <pango/pango.h>
+
+#ifndef __APPLE__
+#include <pango/pangofc-fontmap.h>
+#endif
+
+#include <atk/atk.h>
+
+#include <gdk/gdkkeysyms.h>
+
+#include <math.h>
+
+static GType ags_accessible_level_get_type(void);
+void ags_level_class_init(AgsLevelClass *level);
+void ags_level_init(AgsLevel *level);
+void ags_accessible_level_class_init(AtkObject *object);
+void ags_accessible_level_value_interface_init(AtkValueIface *value);
+void ags_accessible_level_action_interface_init(AtkActionIface *action);
+void ags_level_set_property(GObject *gobject,
+			    guint prop_id,
+			    const GValue *value,
+			    GParamSpec *param_spec);
+void ags_level_get_property(GObject *gobject,
+			    guint prop_id,
+			    GValue *value,
+			    GParamSpec *param_spec);
+void ags_level_finalize(GObject *gobject);
+AtkObject* ags_level_get_accessible(GtkWidget *widget);
+void ags_level_show(GtkWidget *widget);
+
+void ags_accessible_level_get_value_and_text(AtkValue *value,
+					     gdouble *current_value,
+					     gchar **text);
+#ifdef HAVE_ATK_2_12  
+AtkRange* ags_accessible_level_get_range(AtkValue *value);
+#endif
+gdouble ags_accessible_level_get_increment(AtkValue *value);
+void ags_accessible_level_set_value(AtkValue *value,
+				    gdouble new_value);
+
+gboolean ags_accessible_level_do_action(AtkAction *action,
+					gint i);
+gint ags_accessible_level_get_n_actions(AtkAction *action);
+const gchar* ags_accessible_level_get_description(AtkAction *action,
+						  gint i);
+const gchar* ags_accessible_level_get_name(AtkAction *action,
+					   gint i);
+const gchar* ags_accessible_level_get_keybinding(AtkAction *action,
+						 gint i);
+gboolean ags_accessible_level_set_description(AtkAction *action,
+					      gint i);
+gchar* ags_accessible_level_get_localized_name(AtkAction *action,
+					       gint i);
+
+void ags_level_map(GtkWidget *widget);
+void ags_level_realize(GtkWidget *widget);
+void ags_level_size_request(GtkWidget *widget,
+			    GtkRequisition   *requisition);
+void ags_level_size_allocate(GtkWidget *widget,
+			     GtkAllocation *allocation);
+gboolean ags_level_expose(GtkWidget *widget,
+			  GdkEventExpose *event);
+gboolean ags_level_button_press(GtkWidget *widget,
+				GdkEventButton *event);
+gboolean ags_level_button_release(GtkWidget *widget,
+				  GdkEventButton *event);
+gboolean ags_level_key_press(GtkWidget *widget,
+			     GdkEventKey *event);
+gboolean ags_level_key_release(GtkWidget *widget,
+			       GdkEventKey *event);
+gboolean ags_level_motion_notify(GtkWidget *widget,
+				 GdkEventMotion *event);
+
+void ags_level_draw(AgsLevel *level);
+
+/**
+ * SECTION:ags_level
+ * @short_description: A level widget
+ * @title: AgsLevel
+ * @section_id:
+ * @include: ags/widget/ags_level.h
+ *
+ * #AgsLevel is a widget that shows you a meter.
+ */
+
+enum{
+  VALUE_CHANGED,
+  LAST_SIGNAL,
+};
+
+enum{
+  PROP_0,
+  PROP_LOWER,
+  PROP_UPPER,
+  PROP_NORMALIZED_VOLUME,
+};
+
+static gpointer ags_level_parent_class = NULL;
+static guint level_signals[LAST_SIGNAL];
+
+static GQuark quark_accessible_object = 0;
+
+GType
+ags_level_get_type(void)
+{
+  static GType ags_type_level = 0;
+
+  if(!ags_type_level){
+    static const GTypeInfo ags_level_info = {
+      sizeof(AgsLevelClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      (GClassInitFunc) ags_level_class_init,
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof(AgsLevel),
+      0,    /* n_preallocs */
+      (GInstanceInitFunc) ags_level_init,
+    };
+
+    ags_type_level = g_type_register_static(GTK_TYPE_WIDGET,
+					    "AgsLevel", &ags_level_info,
+					    0);
+  }
+
+  return(ags_type_level);
+}
+
+static GType
+ags_accessible_level_get_type(void)
+{
+  static GType ags_type_accessible_level = 0;
+
+  if(!ags_type_accessible_level){
+    const GTypeInfo ags_accesssible_level_info = {
+      sizeof(GtkAccessibleClass),
+      NULL,           /* base_init */
+      NULL,           /* base_finalize */
+      (GClassInitFunc) ags_accessible_level_class_init,
+      NULL,           /* class_finalize */
+      NULL,           /* class_data */
+      sizeof(GtkAccessible),
+      0,             /* n_preallocs */
+      NULL, NULL
+    };
+
+    static const GInterfaceInfo atk_value_interface_info = {
+      (GInterfaceInitFunc) ags_accessible_level_value_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };
+    
+    static const GInterfaceInfo atk_action_interface_info = {
+      (GInterfaceInitFunc) ags_accessible_level_action_interface_init,
+      NULL, /* interface_finalize */
+      NULL, /* interface_data */
+    };
+
+    ags_type_accessible_level = g_type_register_static(GTK_TYPE_ACCESSIBLE,
+						       "AgsAccessibleLevel", &ags_accesssible_level_info,
+						       0);
+
+    g_type_add_interface_static(ags_type_accessible_level,
+				ATK_TYPE_VALUE,
+				&atk_value_interface_info);
+
+    g_type_add_interface_static(ags_type_accessible_level,
+				ATK_TYPE_ACTION,
+				&atk_action_interface_info);
+  }
+  
+  return(ags_type_accessible_level);
+}
+
+void
+ags_level_class_init(AgsLevelClass *level)
+{
+  GObjectClass *gobject;
+  GtkWidgetClass *widget;
+  GParamSpec *param_spec;
+
+  ags_level_parent_class = g_type_class_peek_parent(level);
+
+  quark_accessible_object = g_quark_from_static_string("ags-accessible-object");
+
+  /* GObjectClass */
+  gobject = (GObjectClass *) level;
+
+  gobject->set_property = ags_level_set_property;
+  gobject->get_property = ags_level_get_property;
+
+  gobject->finalize = ags_level_finalize;
+
+  /* properties */
+  /**
+   * AgsLevel:lower:
+   *
+   * The level's lower range.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_double("lower",
+				   "lower",
+				   "The lower of level",
+				   -G_MAXDOUBLE,
+				   G_MAXDOUBLE,
+				   AGS_LEVEL_DEFAULT_LOWER,
+				   G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_LOWER,
+				  param_spec);
+
+  /**
+   * AgsLevel:upper:
+   *
+   * The level's upper range.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_double("upper",
+				   "upper",
+				   "The upper of level",
+				   -G_MAXDOUBLE,
+				   G_MAXDOUBLE,
+				   AGS_LEVEL_DEFAULT_UPPER,
+				   G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_UPPER,
+				  param_spec);
+
+  /**
+   * AgsLevel:normalized-volume:
+   *
+   * The level's default value.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_double("normalized-volume",
+				   "normalized volume",
+				   "The normalized volume of level",
+				   -G_MAXDOUBLE,
+				   G_MAXDOUBLE,
+				   AGS_LEVEL_DEFAULT_NORMALIZED_VOLUME,
+				   G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_NORMALIZED_VOLUME,
+				  param_spec);
+
+  /* GtkWidgetClass */
+  widget = (GtkWidgetClass *) level;
+
+  widget->get_accessible = ags_level_get_accessible;
+  //  widget->map = ags_level_map;
+  widget->realize = ags_level_realize;
+  widget->expose_event = ags_level_expose;
+  widget->size_request = ags_level_size_request;
+  widget->size_allocate = ags_level_size_allocate;
+  widget->button_press_event = ags_level_button_press;
+  widget->button_release_event = ags_level_button_release;
+  widget->key_press_event = ags_level_key_press;
+  widget->key_release_event = ags_level_key_release;
+  widget->motion_notify_event = ags_level_motion_notify;
+  widget->show = ags_level_show;
+
+  /* AgsLevelClass */  
+  level->value_changed = NULL;
+
+  /* signals */
+  /**
+   * AgsLevel::value-changed:
+   * @level: the #AgsLevel
+   * @normalized_volume: the changed default value
+   *
+   * The ::value-changed signal notifies about modified default value.
+   *
+   * Since: 1.4.0
+   */
+  level_signals[VALUE_CHANGED] =
+    g_signal_new("value-changed",
+		 G_TYPE_FROM_CLASS(level),
+		 G_SIGNAL_RUN_LAST,
+		 G_STRUCT_OFFSET(AgsLevelClass, value_changed),
+		 NULL, NULL,
+		 g_cclosure_marshal_VOID__DOUBLE,
+		 G_TYPE_NONE, 1,
+		 G_TYPE_DOUBLE);
+}
+
+void
+ags_accessible_level_class_init(AtkObject *object)
+{
+  /* empty */
+}
+
+void
+ags_accessible_level_value_interface_init(AtkValueIface *value)
+{
+  value->get_current_value = NULL;
+  value->get_maximum_value = NULL;
+  value->get_minimum_value = NULL;
+  value->set_current_value = NULL;
+  value->get_minimum_increment = NULL;
+
+#ifdef HAVE_ATK_2_12  
+  value->get_value_and_text = ags_accessible_level_get_value_and_text;
+  value->get_range = ags_accessible_level_get_range;
+  value->get_increment = ags_accessible_level_get_increment;
+  value->get_sub_ranges = NULL;
+  value->set_value = ags_accessible_level_set_value;
+#endif
+}
+
+void
+ags_accessible_level_action_interface_init(AtkActionIface *action)
+{
+  action->do_action = ags_accessible_level_do_action;
+  action->get_n_actions = ags_accessible_level_get_n_actions;
+  action->get_description = ags_accessible_level_get_description;
+  action->get_name = ags_accessible_level_get_name;
+  action->get_keybinding = ags_accessible_level_get_keybinding;
+  action->set_description = ags_accessible_level_set_description;
+  action->get_localized_name = ags_accessible_level_get_localized_name;
+}
+
+void
+ags_level_init(AgsLevel *level)
+{
+  AtkObject *accessible;
+
+  g_object_set(G_OBJECT(level),
+	       "app-paintable", TRUE,
+	       "can-focus", TRUE,
+	       NULL);
+
+  accessible = gtk_widget_get_accessible((GtkWidget *) level);
+
+  g_object_set(accessible,
+	       "accessible-name", "level",
+	       "accessible-description", "Specify a default value",
+	       NULL);
+
+  level->flags = 0;
+
+  level->key_mask = 0;
+  level->button_state = 0;
+  level->layout = AGS_LEVEL_LAYOUT_VERTICAL;
+
+  level->font_size = 11;
+
+  level->level_width = AGS_LEVEL_DEFAULT_WIDTH;
+  level->level_height = AGS_LEVEL_DEFAULT_HEIGHT;
+
+  level->lower = AGS_LEVEL_DEFAULT_LOWER;
+  level->upper = AGS_LEVEL_DEFAULT_UPPER;
+
+  level->normalized_volume = AGS_LEVEL_DEFAULT_NORMALIZED_VOLUME;
+  
+  level->step_count = AGS_LEVEL_DEFAULT_STEP_COUNT;
+  level->page_size = AGS_LEVEL_DEFAULT_PAGE_SIZE;
+  
+  level->samplerate = AGS_LEVEL_DEFAULT_SAMPLERATE;
+  
+  level->audio_channel = NULL;
+  level->audio_channel_count = 0;
+}
+
+void
+ags_level_set_property(GObject *gobject,
+		       guint prop_id,
+		       const GValue *value,
+		       GParamSpec *param_spec)
+{
+  AgsLevel *level;
+
+  level = AGS_LEVEL(gobject);
+
+  switch(prop_id){
+  case PROP_LOWER:
+    {
+      level->lower = g_value_get_double(value);
+
+      gtk_widget_queue_draw(level);
+    }
+    break;
+  case PROP_UPPER:
+    {
+      level->upper = g_value_get_double(value);
+
+      gtk_widget_queue_draw(level);
+    }
+    break;
+  case PROP_NORMALIZED_VOLUME:
+    {
+      level->normalized_volume = g_value_get_double(value);
+
+      gtk_widget_queue_draw(level);
+    }
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
+    break;
+  }
+}
+
+void
+ags_level_get_property(GObject *gobject,
+		       guint prop_id,
+		       GValue *value,
+		       GParamSpec *param_spec)
+{
+  AgsLevel *level;
+
+  level = AGS_LEVEL(gobject);
+
+  switch(prop_id){
+  case PROP_LOWER:
+    {
+      g_value_set_double(value,
+			 level->lower);
+    }
+    break;
+  case PROP_UPPER:
+    {
+      g_value_set_double(value,
+			 level->upper);
+    }
+    break;
+  case PROP_NORMALIZED_VOLUME:
+    {
+      g_value_set_double(value,
+			 level->normalized_volume);
+    }
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
+    break;
+  }
+}
+
+void
+ags_level_finalize(GObject *gobject)
+{
+  AgsLevel *level;
+
+  level = AGS_LEVEL(gobject);
+
+  /* call parent */
+  G_OBJECT_CLASS(ags_level_parent_class)->finalize(gobject);
+}
+
+void
+ags_accessible_level_get_value_and_text(AtkValue *value,
+					gdouble *current_value,
+					gchar **text)
+{
+  AgsLevel *level;
+  
+  level = (AgsLevel *) gtk_accessible_get_widget(GTK_ACCESSIBLE(value));
+
+  if(current_value != NULL){
+    *current_value = level->normalized_volume;
+  }
+
+  if(text != NULL){
+    *text = g_strdup_printf("%f",
+			    level->normalized_volume);
+  }
+}
+
+#ifdef HAVE_ATK_2_12
+AtkRange*
+ags_accessible_level_get_range(AtkValue *value)
+{
+  AgsLevel *level;
+  AtkRange *range;
+  
+  level = (AgsLevel *) gtk_accessible_get_widget(GTK_ACCESSIBLE(value));
+
+  range = atk_range_new(level->lower,
+			level->upper,
+			"Valid lower and upper input range of this level");
+}
+#endif
+
+gdouble
+ags_accessible_level_get_increment(AtkValue *value)
+{
+  AgsLevel *level;
+
+  level = (AgsLevel *) gtk_accessible_get_widget(GTK_ACCESSIBLE(value));
+
+  return((level->upper - level->lower) / level->step_count);
+}
+
+void
+ags_accessible_level_set_value(AtkValue *value,
+			       gdouble new_value)
+{
+  AgsLevel *level;
+
+  level = (AgsLevel *) gtk_accessible_get_widget(GTK_ACCESSIBLE(value));
+  level->normalized_volume = new_value;
+
+  gtk_widget_queue_draw((GtkWidget *) level);
+}
+
+gboolean
+ags_accessible_level_do_action(AtkAction *action,
+			       gint i)
+{
+  AgsLevel *level;
+  
+  GdkEventKey *key_press, *key_release;
+  
+  if(!(i >= 0 && i < 4)){
+    return(FALSE);
+  }
+
+  level = (AgsLevel *) gtk_accessible_get_widget(GTK_ACCESSIBLE(action));
+  
+  key_press = gdk_event_new(GDK_KEY_PRESS);
+  key_release = gdk_event_new(GDK_KEY_RELEASE);
+
+  switch(i){
+  case AGS_LEVEL_STEP_UP:
+    {
+      key_press->keyval =
+	key_release->keyval = GDK_KEY_Up;
+    
+      /* send event */
+      gtk_widget_event((GtkWidget *) level,
+		       (GdkEvent *) key_press);
+      gtk_widget_event((GtkWidget *) level,
+		       (GdkEvent *) key_release);
+    }
+    break;
+  case AGS_LEVEL_STEP_DOWN:
+    {
+      key_press->keyval =
+	key_release->keyval = GDK_KEY_Down;
+      
+      /* send event */
+      gtk_widget_event((GtkWidget *) level,
+		       (GdkEvent *) key_press);
+      gtk_widget_event((GtkWidget *) level,
+		       (GdkEvent *) key_release);
+    }
+    break;
+  case AGS_LEVEL_PAGE_UP:
+    {
+      key_press->keyval =
+	key_release->keyval = GDK_KEY_Page_Up;
+    
+      /* send event */
+      gtk_widget_event((GtkWidget *) level,
+		       (GdkEvent *) key_press);
+      gtk_widget_event((GtkWidget *) level,
+		       (GdkEvent *) key_release);
+    }
+    break;
+  case AGS_LEVEL_PAGE_DOWN:
+    {
+      key_press->keyval =
+	key_release->keyval = GDK_KEY_Page_Down;
+      
+      /* send event */
+      gtk_widget_event((GtkWidget *) level,
+		       (GdkEvent *) key_press);
+      gtk_widget_event((GtkWidget *) level,
+		       (GdkEvent *) key_release);
+    }
+    break;
+  }
+
+  return(TRUE);
+}
+
+gint
+ags_accessible_level_get_n_actions(AtkAction *action)
+{
+  return(4);
+}
+
+const gchar*
+ags_accessible_level_get_description(AtkAction *action,
+				     gint i)
+{
+  static const gchar *actions[] = {
+    "step up level default value",
+    "step down level default value",
+    "page up level default value",
+    "page down level default value",
+  };
+
+  if(i >= 0 && i < 4){
+    return(actions[i]);
+  }else{
+    return(NULL);
+  }
+}
+
+const gchar*
+ags_accessible_level_get_name(AtkAction *action,
+			      gint i)
+{
+  static const gchar *actions[] = {
+    "step-up",
+    "step-down",
+    "page-up",
+    "page-down",
+  };
+  
+  if(i >= 0 && i < 4){
+    return(actions[i]);
+  }else{
+    return(NULL);
+  }
+}
+
+const gchar*
+ags_accessible_level_get_keybinding(AtkAction *action,
+				    gint i)
+{
+  static const gchar *actions[] = {
+    "up",
+    "down",
+    "page-up",
+    "page-down",
+  };
+  
+  if(i >= 0 && i < 4){
+    return(actions[i]);
+  }else{
+    return(NULL);
+  }
+}
+
+gboolean
+ags_accessible_level_set_description(AtkAction *action,
+				     gint i)
+{
+  //TODO:JK: implement me
+
+  return(FALSE);
+}
+
+gchar*
+ags_accessible_level_get_localized_name(AtkAction *action,
+					gint i)
+{
+  //TODO:JK: implement me
+
+  return(NULL);
+}
+
+void
+ags_level_map(GtkWidget *widget)
+{
+  if(gtk_widget_get_realized (widget) && !gtk_widget_get_mapped(widget)){
+    GTK_WIDGET_CLASS(ags_level_parent_class)->map(widget);
+    
+    gdk_window_show(widget->window);
+    ags_level_draw((AgsLevel *) widget);
+  }
+}
+
+void
+ags_level_realize(GtkWidget *widget)
+{
+  AgsLevel *level;
+
+  GdkWindowAttr attributes;
+
+  gint attributes_mask;
+
+  g_return_if_fail(widget != NULL);
+  g_return_if_fail(AGS_IS_LEVEL(widget));
+
+  level = AGS_LEVEL(widget);
+
+  gtk_widget_set_realized(widget, TRUE);
+
+  /*  */
+  attributes.window_type = GDK_WINDOW_CHILD;
+  
+  attributes.x = widget->allocation.x;
+  attributes.y = widget->allocation.y;
+  attributes.width = AGS_LEVEL_DEFAULT_WIDTH;
+  attributes.height = AGS_LEVEL_DEFAULT_HEIGHT;
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+  attributes.event_mask = gtk_widget_get_events (widget);
+  attributes.event_mask |= (GDK_EXPOSURE_MASK);
+
+  widget->window = gdk_window_new(gtk_widget_get_parent_window (widget),
+				  &attributes, attributes_mask);
+  gdk_window_set_user_data(widget->window, level);
+
+  widget->style = gtk_style_attach(widget->style,
+				   widget->window);
+  gtk_style_set_background(widget->style,
+			   widget->window,
+			   GTK_STATE_NORMAL);
+
+  gtk_widget_queue_resize(widget);
+}
+
+AtkObject*
+ags_level_get_accessible(GtkWidget *widget)
+{
+  AtkObject* accessible;
+
+  accessible = g_object_get_qdata(G_OBJECT(widget),
+				  quark_accessible_object);
+  
+  if(!accessible){
+    accessible = g_object_new(ags_accessible_level_get_type(),
+			      NULL);
+    
+    g_object_set_qdata(G_OBJECT(widget),
+		       quark_accessible_object,
+		       accessible);
+    gtk_accessible_set_widget(GTK_ACCESSIBLE(accessible),
+			      widget);
+  }
+  
+  return(accessible);
+}
+
+void
+ags_level_show(GtkWidget *widget)
+{
+  GTK_WIDGET_CLASS(ags_level_parent_class)->show(widget);
+}
+
+void
+ags_level_size_request(GtkWidget *widget,
+		       GtkRequisition *requisition)
+{
+  AgsLevel *level;
+
+  level = AGS_LEVEL(widget);
+
+  if(level->layout == AGS_LEVEL_LAYOUT_VERTICAL){
+    requisition->width = level->level_width;
+    requisition->height = level->level_height;
+  }else if(level->layout == AGS_LEVEL_LAYOUT_HORIZONTAL){
+    requisition->width = level->level_height;
+    requisition->height = level->level_width;
+  }
+}
+
+void
+ags_level_size_allocate(GtkWidget *widget,
+			GtkAllocation *allocation)
+{
+  AgsLevel *level;
+
+  GdkWindow *window;
+    
+  level = AGS_LEVEL(widget);
+  
+  widget->allocation = *allocation;
+  
+  window = gtk_widget_get_window(widget);
+  gdk_window_move(window,
+		  allocation->x, allocation->y);
+
+  if(level->layout == AGS_LEVEL_LAYOUT_VERTICAL){
+    widget->allocation.width = level->level_width;
+    widget->allocation.height = level->level_height;
+
+    allocation->height = level->level_height;
+  }else if(level->layout == AGS_LEVEL_LAYOUT_HORIZONTAL){
+    widget->allocation.width = level->level_height;
+    widget->allocation.height = level->level_width;
+
+    allocation->width = level->level_height;
+  }
+}
+
+gboolean
+ags_level_expose(GtkWidget *widget,
+		 GdkEventExpose *event)
+{
+  ags_level_draw(AGS_LEVEL(widget));
+
+  return(FALSE);
+}
+
+gboolean
+ags_level_button_press(GtkWidget *widget,
+		       GdkEventButton *event)
+{
+  AgsLevel *level;
+
+  guint width, height;
+  guint x_start, y_start;
+
+  level = AGS_LEVEL(widget);
+
+  width = widget->allocation.width;
+  height = widget->allocation.height;
+
+  x_start = 0;
+  y_start = 0;
+
+  if(event->x >= x_start &&
+     event->x < width &&
+     event->y >= y_start &&
+     event->y < height){
+    if(event->button == 1){
+      gdouble c_range;
+      gdouble normalized_volume;
+      
+      level->button_state |= AGS_LEVEL_BUTTON_1_PRESSED;
+
+      c_range = level->upper - level->lower;
+      
+      if(level->layout == AGS_LEVEL_LAYOUT_VERTICAL){
+	normalized_volume = event->y / c_range;
+      }else if(level->layout == AGS_LEVEL_LAYOUT_HORIZONTAL){
+	normalized_volume = event->x / c_range;
+      }
+
+      level->normalized_volume = normalized_volume;
+      gtk_widget_queue_draw(level);
+
+      ags_level_value_changed(level,
+			      normalized_volume);
+    }
+  }
+  
+  return(FALSE);
+}
+
+gboolean
+ags_level_button_release(GtkWidget *widget,
+			 GdkEventButton *event)
+{
+  AgsLevel *level;
+
+  gtk_widget_grab_focus(widget);
+
+  level = AGS_LEVEL(widget);
+  
+  if(event->button == 1){
+    if((AGS_LEVEL_BUTTON_1_PRESSED & (level->button_state)) != 0){
+      gdouble c_range;
+      gdouble normalized_volume;
+      
+      level->button_state |= AGS_LEVEL_BUTTON_1_PRESSED;
+
+      c_range = level->upper - level->lower;
+      
+      if(level->layout == AGS_LEVEL_LAYOUT_VERTICAL){
+	normalized_volume = event->y / c_range;
+      }else if(level->layout == AGS_LEVEL_LAYOUT_HORIZONTAL){
+	normalized_volume = event->x / c_range;
+      }
+
+      level->normalized_volume = normalized_volume;
+      gtk_widget_queue_draw(level);
+
+      ags_level_value_changed(level,
+			      normalized_volume);
+    }
+    
+    level->button_state &= (~AGS_LEVEL_BUTTON_1_PRESSED);
+  }
+
+  return(FALSE);
+}
+
+gboolean
+ags_level_key_press(GtkWidget *widget,
+		    GdkEventKey *event)
+{
+  if(event->keyval == GDK_KEY_Tab ||
+     event->keyval == GDK_ISO_Left_Tab ||
+     event->keyval == GDK_KEY_Shift_L ||
+     event->keyval == GDK_KEY_Shift_R ||
+     event->keyval == GDK_KEY_Alt_L ||
+     event->keyval == GDK_KEY_Alt_R ||
+     event->keyval == GDK_KEY_Control_L ||
+     event->keyval == GDK_KEY_Control_R ){
+    return(GTK_WIDGET_CLASS(ags_level_parent_class)->key_press_event(widget, event));
+  }
+
+  return(TRUE);
+}
+
+gboolean
+ags_level_key_release(GtkWidget *widget,
+		      GdkEventKey *event)
+{
+  AgsLevel *level;
+
+  //TODO:JK: implement me
+  
+  if(event->keyval == GDK_KEY_Tab ||
+     event->keyval == GDK_ISO_Left_Tab ||
+     event->keyval == GDK_KEY_Shift_L ||
+     event->keyval == GDK_KEY_Shift_R ||
+     event->keyval == GDK_KEY_Alt_L ||
+     event->keyval == GDK_KEY_Alt_R ||
+     event->keyval == GDK_KEY_Control_L ||
+     event->keyval == GDK_KEY_Control_R ){
+    return(GTK_WIDGET_CLASS(ags_level_parent_class)->key_release_event(widget, event));
+  }
+
+  level = AGS_LEVEL(widget);
+  
+  switch(event->keyval){
+  case GDK_KEY_Up:
+  case GDK_KEY_uparrow:
+    {
+      gdouble c_range;
+      gdouble step;
+
+      c_range = level->upper - level->lower;
+      
+      step = c_range / level->step_count;
+
+      if(level->normalized_volume + log(step) > level->upper){
+	level->normalized_volume = level->upper;
+      }else{
+	level->normalized_volume += log(step);
+      }
+
+      gtk_widget_queue_draw(widget);
+
+      ags_level_value_changed(level,
+			      level->normalized_volume);
+    }
+    break;
+  case GDK_KEY_Down:
+  case GDK_KEY_downarrow:
+    {
+      gdouble c_range;
+      gdouble step;
+
+      c_range = level->upper - level->lower;
+      
+      step = c_range / level->step_count;
+
+      if(level->normalized_volume - log(step) < level->lower){
+	level->normalized_volume = level->lower;
+      }else{
+	level->normalized_volume -= log(step);
+      }
+
+      gtk_widget_queue_draw(widget);
+
+      ags_level_value_changed(level,
+			      level->normalized_volume);
+    }
+    break;
+  case GDK_KEY_Page_Up:
+  case GDK_KEY_KP_Page_Up:
+    {
+      gdouble c_range;
+      gdouble page;
+
+      c_range = level->upper - level->lower;
+      
+      page = level->page_size * (c_range / level->step_count);
+
+      if(level->normalized_volume + log(page) > level->upper){
+	level->normalized_volume = level->upper;
+      }else{
+	level->normalized_volume += log(page);
+      }
+
+      gtk_widget_queue_draw(widget);
+
+      ags_level_value_changed(level,
+			      level->normalized_volume);
+    }
+    break;
+  case GDK_KEY_Page_Down:
+  case GDK_KEY_KP_Page_Down:
+    {
+      gdouble c_range;
+      gdouble page;
+
+      c_range = level->upper - level->lower;
+      
+      page = level->page_size * (c_range / level->step_count);
+
+      if(level->normalized_volume - log(page) < level->lower){
+	level->normalized_volume = level->lower;
+      }else{
+	level->normalized_volume -= log(page);
+      }
+
+      gtk_widget_queue_draw(widget);
+
+      ags_level_value_changed(level,
+			      level->normalized_volume);
+    }
+    break;
+  }
+  
+  return(TRUE);
+}
+
+gboolean
+ags_level_motion_notify(GtkWidget *widget,
+			GdkEventMotion *event)
+{
+  AgsLevel *level;
+
+  guint width, height;
+  guint x_start, y_start;
+  
+  level = AGS_LEVEL(widget);
+
+  width = widget->allocation.width;
+  height = widget->allocation.height;
+
+  x_start = 0;
+  y_start = 0;
+
+  if((AGS_LEVEL_BUTTON_1_PRESSED & (level->button_state)) != 0){
+    gdouble c_range;
+    gdouble new_normalized_volume;
+      
+    level->button_state |= AGS_LEVEL_BUTTON_1_PRESSED;
+
+    c_range = level->upper - level->lower;
+      
+    if(level->layout == AGS_LEVEL_LAYOUT_VERTICAL){
+      new_normalized_volume = event->y / c_range;
+    }else if(level->layout == AGS_LEVEL_LAYOUT_HORIZONTAL){
+      new_normalized_volume = event->x / c_range;
+    }
+
+    if(new_normalized_volume != level->normalized_volume){
+      level->normalized_volume = new_normalized_volume;
+      gtk_widget_queue_draw(level);
+      
+      ags_level_value_changed(level,
+			      new_normalized_volume);
+    }
+  }
+    
+  return(FALSE);
+}
+
+void
+ags_level_draw(AgsLevel *level)
+{
+  cairo_t *cr;
+
+  gchar *str;
+  
+  guint width, height;
+  guint x_start, y_start;
+
+  void ags_level_draw_string(cairo_t *cr, gchar *str){
+    PangoLayout *layout;
+    PangoFontDescription *desc;
+
+    layout = pango_cairo_create_layout(cr);
+    pango_layout_set_text(layout, str, -1);
+    desc = pango_font_description_from_string("Sans Slant"); //pango_font_description_copy_static("Georgia Bold 11");
+    pango_font_description_set_size(desc,
+				    level->font_size * PANGO_SCALE);
+    pango_layout_set_font_description(layout, desc);
+    pango_font_description_free(desc);
+
+    pango_cairo_update_layout(cr, layout);
+    pango_cairo_show_layout(cr, layout);
+
+#ifndef __APPLE__
+    pango_fc_font_map_cache_clear(pango_cairo_font_map_get_default());
+#endif
+    g_object_unref(layout);
+  }
+  
+  static const gdouble white_gc = 65535.0;
+
+  if(!AGS_IS_LEVEL(level)){
+    return;
+  }
+
+  cr = gdk_cairo_create(GTK_WIDGET(level)->window);
+  
+  if(cr == NULL){
+    return;
+  }
+  
+  width = GTK_WIDGET(level)->allocation.width;
+  height = GTK_WIDGET(level)->allocation.height;
+  
+  x_start = 0;
+  y_start = 0;
+
+  cairo_surface_flush(cairo_get_target(cr));
+  cairo_push_group(cr);
+
+  /* background */
+  cairo_set_source_rgb(cr,
+		       0.0, 0.0, 0.0);
+  cairo_rectangle(cr,
+		  (gdouble) x_start, (gdouble) y_start,
+		  (gdouble) width, (gdouble) height);
+  cairo_fill(cr);
+
+  /* box */
+  cairo_set_source_rgb(cr,
+		       0.5, 0.4, 0.0);
+  cairo_set_line_width(cr,
+		       1.0);
+  cairo_rectangle(cr,
+		  (gdouble) x_start, (gdouble) y_start,
+		  (gdouble) width, (gdouble) height);
+  cairo_stroke(cr);
+
+  /* draw level */
+  //TODO:JK: implement me
+
+  /* show samplerate */
+  str = g_strdup_printf("%u", level->samplerate);
+  
+  cairo_set_source_rgb(cr,
+		       1.0, 1.0, 1.0);
+
+  if(level->layout == AGS_LEVEL_LAYOUT_VERTICAL){
+    cairo_move_to(cr,
+		  x_start + level->font_size, y_start + height - 1.0);
+    cairo_rotate(cr,
+		 2 * M_PI * 0.75);
+  }else{
+    cairo_move_to(cr,
+		  x_start + level->font_size, y_start + 1.0);
+  }
+  
+  ags_level_draw_string(cr,
+			str);
+
+  cairo_pop_group_to_source(cr);
+  cairo_paint(cr);
+
+  cairo_surface_mark_dirty(cairo_get_target(cr));
+  cairo_destroy(cr);
+}
+
+/**
+ * ags_level_value_changed:
+ * @level: the #AgsLevel
+ * @normalized_volume: the normalized volume
+ * 
+ * Emits ::value-changed event.
+ * 
+ * Since: 1.4.0
+ */
+void
+ags_level_value_changed(AgsLevel *level,
+			 gdouble normalized_volume)
+{
+  g_return_if_fail(AGS_IS_LEVEL(level));
+  
+  g_object_ref((GObject *) level);
+  g_signal_emit(G_OBJECT(level),
+		level_signals[VALUE_CHANGED], 0,
+		normalized_volume);
+  g_object_unref((GObject *) level);
+}
+
+/**
+ * ags_level_new:
+ * 
+ * Create a new instance of #AgsLevel.
+ * 
+ * Returns: the new #AgsLevel instance
+ * 
+ * Since: 1.4.0
+ */
+AgsLevel*
+ags_level_new()
+{
+  AgsLevel *level;
+
+  level = (AgsLevel *) g_object_new(AGS_TYPE_LEVEL,
+				    NULL);
+  
+  return(level);
+}
diff --git a/ags/X/editor/ags_level.h b/ags/widget/ags_level.h
similarity index 51%
rename from ags/X/editor/ags_level.h
rename to ags/widget/ags_level.h
index 5de97ca..5ce6e9f 100644
--- a/ags/X/editor/ags_level.h
+++ b/ags/widget/ags_level.h
@@ -25,8 +25,6 @@
 
 #include <gtk/gtk.h>
 
-#include <cairo.h>
-
 #define AGS_TYPE_LEVEL                (ags_level_get_type())
 #define AGS_LEVEL(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_LEVEL, AgsLevel))
 #define AGS_LEVEL_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_LEVEL, AgsLevelClass))
@@ -34,24 +32,93 @@
 #define AGS_IS_LEVEL_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_LEVEL))
 #define AGS_LEVEL_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS (obj, AGS_TYPE_LEVEL, AgsLevelClass))
 
+#define AGS_LEVEL_DEFAULT_WIDTH (60)
+#define AGS_LEVEL_DEFAULT_HEIGHT (256)
+
+#define AGS_LEVEL_DEFAULT_LOWER (0.0)
+#define AGS_LEVEL_DEFAULT_UPPER (1.0)
+#define AGS_LEVEL_DEFAULT_NORMALIZED_VOLUME (0.0)
+
+#define AGS_LEVEL_DEFAULT_STEP_COUNT (0.1)
+#define AGS_LEVEL_DEFAULT_PAGE_SIZE (0.25)
+
+#define AGS_LEVEL_DEFAULT_SAMPLERATE (44100)
+
 typedef struct _AgsLevel AgsLevel;
 typedef struct _AgsLevelClass AgsLevelClass;
 
+typedef enum{
+  AGS_LEVEL_PCM_S8              = 1,
+  AGS_LEVEL_PCM_S16             = 1 <<  1,
+  AGS_LEVEL_PCM_S24             = 1 <<  2,
+  AGS_LEVEL_PCM_S32             = 1 <<  3,
+  AGS_LEVEL_PCM_S64             = 1 <<  4,
+  AGS_LEVEL_PCM_FLOAT           = 1 <<  5,
+  AGS_LEVEL_PCM_DOUBLE          = 1 <<  6,
+}AgsLevelFlags;
+
+typedef enum{
+  AGS_LEVEL_BUTTON_1_PRESSED     = 1,
+}AgsLevelButtonState;
+
+typedef enum{
+  AGS_LEVEL_KEY_L_CONTROL       = 1,
+  AGS_LEVEL_KEY_R_CONTROL       = 1 <<  1,
+  AGS_LEVEL_KEY_L_SHIFT         = 1 <<  2,
+  AGS_LEVEL_KEY_R_SHIFT         = 1 <<  3,
+}AgsLevelKeyMask;
+
+typedef enum{
+  AGS_LEVEL_LAYOUT_VERTICAL,
+  AGS_LEVEL_LAYOUT_HORIZONTAL,
+}AgsLevelLayout;
+
+typedef enum{
+  AGS_LEVEL_STEP_UP,
+  AGS_LEVEL_STEP_DOWN,
+  AGS_LEVEL_PAGE_UP,
+  AGS_LEVEL_PAGE_DOWN,
+}AgsLevelAction;
+
 struct _AgsLevel
 {
-  GtkDrawingArea drawing_area;
+  GtkWidget widget;
+
+  guint flags;
+
+  guint key_mask;
+  guint button_state;
+  guint layout;
+
+  guint font_size;
+
+  guint level_width;
+  guint level_height;
+
+  gdouble lower;
+  gdouble upper;
+
+  gdouble normalized_volume;
+
+  guint step_count;
+  gdouble page_size;
+
+  guint samplerate;
+  
+  guint *audio_channel;
+  guint audio_channel_count;
 };
 
 struct _AgsLevelClass
 {
-  GtkDrawingAreaClass drawing_area;
+  GtkWidgetClass widget;
+
+  void (*value_changed)(AgsLevel *level,
+			gdouble normalized_volume);
 };
 
 GType ags_level_get_type(void);
 
-void ags_level_paint(AgsLevel *level,
-		     cairo_t *cr);
-
 AgsLevel* ags_level_new();
 
 #endif /*__AGS_LEVEL_H__*/
diff --git a/ags/widget/ags_level_box.c b/ags/widget/ags_level_box.c
new file mode 100644
index 0000000..04b4522
--- /dev/null
+++ b/ags/widget/ags_level_box.c
@@ -0,0 +1,247 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2017 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/widget/ags_level_box.h>
+#include <ags/widget/ags_level.h>
+
+void ags_level_box_class_init(AgsLevelBoxClass *level_box);
+void ags_level_box_init(AgsLevelBox *level_box);
+void ags_level_box_set_property(GObject *gobject,
+				guint prop_id,
+				const GValue *value,
+				GParamSpec *param_spec);
+void ags_level_box_get_property(GObject *gobject,
+				guint prop_id,
+				GValue *value,
+				GParamSpec *param_spec);
+void ags_level_box_finalize(GObject *gobject);
+
+GType ags_level_box_child_type(GtkContainer *container);
+
+/**
+ * SECTION:ags_level_box
+ * @short_description: abstract box widget
+ * @title: AgsLevelBox
+ * @section_id:
+ * @include: ags/widget/ags_level_box.h
+ *
+ * The #AgsLevelBox is an abstract box widget containing #AgsLevel.
+ */
+
+enum{
+  PROP_0,
+  PROP_FIXED_LEVEL_WIDTH,
+  PROP_FIXED_LEVEL_HEIGHT,
+};
+
+static gpointer ags_level_box_parent_class = NULL;
+
+GType
+ags_level_box_get_type(void)
+{
+  static GType ags_type_level_box = 0;
+
+  if(!ags_type_level_box){
+    static const GTypeInfo ags_level_box_info = {
+      sizeof (AgsLevelBoxClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      (GClassInitFunc) ags_level_box_class_init,
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof (AgsLevelBox),
+      0,    /* n_preallocs */
+      (GInstanceInitFunc) ags_level_box_init,
+    };
+
+    ags_type_level_box = g_type_register_static(GTK_TYPE_BOX,
+						"AgsLevelBox", &ags_level_box_info,
+						0);
+  }
+  
+  return(ags_type_level_box);
+}
+
+void
+ags_level_box_class_init(AgsLevelBoxClass *level_box)
+{
+  GObjectClass *gobject;
+  GtkWidgetClass *widget;
+  GtkContainerClass *container;
+
+  GParamSpec *param_spec;
+
+  ags_level_box_parent_class = g_type_class_peek_parent(level_box);
+
+  /* GObjectClass */
+  gobject = (GObjectClass *) level_box;
+
+  gobject->set_property = ags_level_box_set_property;
+  gobject->get_property = ags_level_box_get_property;
+
+  gobject->finalize = ags_level_box_finalize;
+
+  /* properties */
+  /**
+   * AgsLevelBox:fixed-level-width:
+   *
+   * The fixed width of a level.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_uint("fixed-level-width",
+				 "fixed level width",
+				 "The fixed width of a level",
+				 0,
+				 G_MAXUINT,
+				 AGS_LEVEL_BOX_DEFAULT_FIXED_LEVEL_WIDTH,
+				 G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_FIXED_LEVEL_WIDTH,
+				  param_spec);
+
+  /**
+   * AgsLevelBox:fixed-level-height:
+   *
+   * The fixed height of a level.
+   * 
+   * Since: 1.4.0
+   */
+  param_spec = g_param_spec_uint("fixed-level-height",
+				 "fixed level height",
+				 "The fixed height of a level",
+				 0,
+				 G_MAXUINT,
+				 AGS_LEVEL_BOX_DEFAULT_FIXED_LEVEL_HEIGHT,
+				 G_PARAM_READABLE | G_PARAM_WRITABLE);
+  g_object_class_install_property(gobject,
+				  PROP_FIXED_LEVEL_HEIGHT,
+				  param_spec);
+
+  /* GtkWidgetClass */
+  widget = (GtkWidgetClass *) level_box;
+
+  /* GtkContainerClass */
+  container = (GtkWidgetClass *) level_box;
+
+  container->child_type = ags_level_box_child_type;
+}
+
+void
+ags_level_box_init(AgsLevelBox *level_box)
+{
+  g_object_set(level_box,
+	       "homogeneous", FALSE,
+	       "spacing", 0,
+	       NULL);
+  
+  level_box->flags = 0;
+
+  level_box->fixed_level_width = AGS_LEVEL_BOX_DEFAULT_FIXED_LEVEL_WIDTH;
+  level_box->fixed_level_height = AGS_LEVEL_BOX_DEFAULT_FIXED_LEVEL_HEIGHT;
+}
+
+void
+ags_level_box_set_property(GObject *gobject,
+			   guint prop_id,
+			   const GValue *value,
+			   GParamSpec *param_spec)
+{
+  AgsLevelBox *level_box;
+
+  level_box = AGS_LEVEL_BOX(gobject);
+
+  switch(prop_id){
+  case PROP_FIXED_LEVEL_WIDTH:
+    {
+      level_box->fixed_level_width = g_value_get_uint(value);
+    }
+    break;
+  case PROP_FIXED_LEVEL_HEIGHT:
+    {
+      level_box->fixed_level_height = g_value_get_uint(value);
+    }
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
+    break;
+  }
+}
+
+void
+ags_level_box_get_property(GObject *gobject,
+			   guint prop_id,
+			   GValue *value,
+			   GParamSpec *param_spec)
+{
+  AgsLevelBox *level_box;
+
+  level_box = AGS_LEVEL_BOX(gobject);
+
+  switch(prop_id){
+  case PROP_FIXED_LEVEL_WIDTH:
+    {
+      g_value_set_uint(value,
+		       level_box->fixed_level_width);
+    }
+    break;
+  case PROP_FIXED_LEVEL_HEIGHT:
+    {
+      g_value_set_uint(value,
+		       level_box->fixed_level_height);
+    }
+    break;
+  default:
+    G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
+    break;
+  }
+}
+
+void
+ags_level_box_finalize(GObject *gobject)
+{
+  /* call parent */
+  G_OBJECT_CLASS(ags_level_box_parent_class)->finalize(gobject);
+}
+
+GType
+ags_level_box_child_type(GtkContainer *container)
+{
+  return(AGS_TYPE_LEVEL);
+}
+
+/**
+ * ags_level_box_new:
+ * 
+ * Create a new instance of #AgsLevelBox.
+ * 
+ * Returns: the new #AgsLevelBox instance
+ * 
+ * Since: 1.4.0
+ */
+AgsLevelBox*
+ags_level_box_new()
+{
+  AgsLevelBox *level_box;
+
+  level_box = (AgsLevelBox *) g_object_new(AGS_TYPE_LEVEL_BOX,
+					   NULL);
+  
+  return(level_box);
+}
diff --git a/ags/widget/ags_level_box.h b/ags/widget/ags_level_box.h
new file mode 100644
index 0000000..1bbed8a
--- /dev/null
+++ b/ags/widget/ags_level_box.h
@@ -0,0 +1,64 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2017 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_LEVEL_BOX_H__
+#define __AGS_LEVEL_BOX_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+#define AGS_TYPE_LEVEL_BOX                (ags_level_box_get_type())
+#define AGS_LEVEL_BOX(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_LEVEL_BOX, AgsLevelBox))
+#define AGS_LEVEL_BOX_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_LEVEL_BOX, AgsLevelBoxClass))
+#define AGS_IS_LEVEL_BOX(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AGS_TYPE_LEVEL_BOX))
+#define AGS_IS_LEVEL_BOX_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_LEVEL_BOX))
+#define AGS_LEVEL_BOX_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS (obj, AGS_TYPE_LEVEL_BOX, AgsLevelBoxClass))
+
+#define AGS_LEVEL_BOX_DEFAULT_FIXED_LEVEL_WIDTH (60)
+#define AGS_LEVEL_BOX_DEFAULT_FIXED_LEVEL_HEIGHT (128)
+
+typedef struct _AgsLevelBox AgsLevelBox;
+typedef struct _AgsLevelBoxClass AgsLevelBoxClass;
+
+typedef enum{
+  AGS_LEVEL_BOX_FIXED_LEVEL_SIZE  = 1,
+}AgsLevelBoxFlags;
+
+struct _AgsLevelBox
+{
+  GtkBox box;
+
+  guint flags;
+
+  guint fixed_level_width;
+  guint fixed_level_height;
+};
+
+struct _AgsLevelBoxClass
+{
+  GtkBoxClass box;
+};
+
+GType ags_level_box_get_type(void);
+
+AgsLevelBox* ags_level_box_new();
+
+#endif /*__AGS_LEVEL_BOX_H__*/
diff --git a/ags/widget/ags_piano.c b/ags/widget/ags_piano.c
index 2bc2fde..31e174a 100644
--- a/ags/widget/ags_piano.c
+++ b/ags/widget/ags_piano.c
@@ -27,6 +27,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <math.h>
 
 static GType ags_accessible_piano_get_type(void);
 void ags_piano_class_init(AgsPianoClass *piano);
diff --git a/ags/widget/ags_scale.c b/ags/widget/ags_scale.c
index 2be9811..13ab073 100644
--- a/ags/widget/ags_scale.c
+++ b/ags/widget/ags_scale.c
@@ -1244,7 +1244,7 @@ ags_scale_draw(AgsScale *scale)
  */
 void
 ags_scale_value_changed(AgsScale *scale,
-			 gdouble default_value)
+			gdouble default_value)
 {
   g_return_if_fail(AGS_IS_SCALE(scale));
   
diff --git a/ags/widget/ags_scale.h b/ags/widget/ags_scale.h
index 234a1e5..2ca5813 100644
--- a/ags/widget/ags_scale.h
+++ b/ags/widget/ags_scale.h
@@ -112,6 +112,9 @@ struct _AgsScaleClass
 
 GType ags_scale_get_type(void);
 
+void ags_scale_value_changed(AgsScale *scale,
+			     gdouble default_value);
+
 AgsScale* ags_scale_new();
 
 #endif /*__AGS_SCALE_H__*/
diff --git a/ags/widget/ags_scrolled_scale_box.c b/ags/widget/ags_scrolled_level_box.c
similarity index 50%
copy from ags/widget/ags_scrolled_scale_box.c
copy to ags/widget/ags_scrolled_level_box.c
index 39408a8..0e7cc1a 100644
--- a/ags/widget/ags_scrolled_scale_box.c
+++ b/ags/widget/ags_scrolled_level_box.c
@@ -17,36 +17,36 @@
  * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <ags/widget/ags_scrolled_scale_box.h>
+#include <ags/widget/ags_scrolled_level_box.h>
 
-#include <ags/widget/ags_scale.h>
-#include <ags/widget/ags_vscale_box.h>
+#include <ags/widget/ags_level.h>
+#include <ags/widget/ags_vlevel_box.h>
 
-void ags_scrolled_scale_box_class_init(AgsScrolledScaleBoxClass *scrolled_scale_box);
-void ags_scrolled_scale_box_init(AgsScrolledScaleBox *scrolled_scale_box);
-void ags_scrolled_scale_box_set_property(GObject *gobject,
+void ags_scrolled_level_box_class_init(AgsScrolledLevelBoxClass *scrolled_level_box);
+void ags_scrolled_level_box_init(AgsScrolledLevelBox *scrolled_level_box);
+void ags_scrolled_level_box_set_property(GObject *gobject,
 					 guint prop_id,
 					 const GValue *value,
 					 GParamSpec *param_spec);
-void ags_scrolled_scale_box_get_property(GObject *gobject,
+void ags_scrolled_level_box_get_property(GObject *gobject,
 					 guint prop_id,
 					 GValue *value,
 					 GParamSpec *param_spec);
-void ags_scrolled_scale_box_finalize(GObject *gobject);
+void ags_scrolled_level_box_finalize(GObject *gobject);
 
-void ags_scrolled_scale_box_size_allocate(GtkWidget *widget,
+void ags_scrolled_level_box_size_allocate(GtkWidget *widget,
 					  GtkAllocation *allocation);
-void ags_scrolled_scale_box_size_request(GtkWidget *widget,
+void ags_scrolled_level_box_size_request(GtkWidget *widget,
 					 GtkRequisition *requisition);
 
 /**
- * SECTION:ags_scrolled_scale_box
- * @short_description: scrolled scale box widget
- * @title: AgsScrolledScaleBox
+ * SECTION:ags_scrolled_level_box
+ * @short_description: scrolled level box widget
+ * @title: AgsScrolledLevelBox
  * @section_id:
- * @include: ags/widget/ags_scrolled_scale_box.h
+ * @include: ags/widget/ags_scrolled_level_box.h
  *
- * The #AgsScrolledScaleBox lets you to have a scrolled scale box widget.
+ * The #AgsScrolledLevelBox lets you to have a scrolled level box widget.
  */
 
 enum{
@@ -57,59 +57,59 @@ enum{
   PROP_MARGIN_RIGHT,
 };
 
-static gpointer ags_scrolled_scale_box_parent_class = NULL;
+static gpointer ags_scrolled_level_box_parent_class = NULL;
 
 GType
-ags_scrolled_scale_box_get_type(void)
+ags_scrolled_level_box_get_type(void)
 {
-  static GType ags_type_scrolled_scale_box = 0;
+  static GType ags_type_scrolled_level_box = 0;
 
-  if(!ags_type_scrolled_scale_box){
-    static const GTypeInfo ags_scrolled_scale_box_info = {
-      sizeof (AgsScrolledScaleBoxClass),
+  if(!ags_type_scrolled_level_box){
+    static const GTypeInfo ags_scrolled_level_box_info = {
+      sizeof (AgsScrolledLevelBoxClass),
       NULL, /* base_init */
       NULL, /* base_finalize */
-      (GClassInitFunc) ags_scrolled_scale_box_class_init,
+      (GClassInitFunc) ags_scrolled_level_box_class_init,
       NULL, /* class_finalize */
       NULL, /* class_data */
-      sizeof (AgsScrolledScaleBox),
+      sizeof (AgsScrolledLevelBox),
       0,    /* n_preallocs */
-      (GInstanceInitFunc) ags_scrolled_scale_box_init,
+      (GInstanceInitFunc) ags_scrolled_level_box_init,
     };
 
-    ags_type_scrolled_scale_box = g_type_register_static(GTK_TYPE_BIN,
-							 "AgsScrolledScaleBox", &ags_scrolled_scale_box_info,
+    ags_type_scrolled_level_box = g_type_register_static(GTK_TYPE_BIN,
+							 "AgsScrolledLevelBox", &ags_scrolled_level_box_info,
 							 0);
   }
   
-  return(ags_type_scrolled_scale_box);
+  return(ags_type_scrolled_level_box);
 }
 
 void
-ags_scrolled_scale_box_class_init(AgsScrolledScaleBoxClass *scrolled_scale_box)
+ags_scrolled_level_box_class_init(AgsScrolledLevelBoxClass *scrolled_level_box)
 {
   GObjectClass *gobject;
   GtkWidgetClass *widget;
 
   GParamSpec *param_spec;
 
-  ags_scrolled_scale_box_parent_class = g_type_class_peek_parent(scrolled_scale_box);
+  ags_scrolled_level_box_parent_class = g_type_class_peek_parent(scrolled_level_box);
 
   /* GObjectClass */
-  gobject = (GObjectClass *) scrolled_scale_box;
+  gobject = (GObjectClass *) scrolled_level_box;
 
-  gobject->set_property = ags_scrolled_scale_box_set_property;
-  gobject->get_property = ags_scrolled_scale_box_get_property;
+  gobject->set_property = ags_scrolled_level_box_set_property;
+  gobject->get_property = ags_scrolled_level_box_get_property;
 
-  gobject->finalize = ags_scrolled_scale_box_finalize;
+  gobject->finalize = ags_scrolled_level_box_finalize;
 
   /* properties */  
   /**
-   * AgsScrolledScaleBox:margin-top:
+   * AgsScrolledLevelBox:margin-top:
    *
    * The margin top.
    * 
-   * Since: 1.3.0
+   * Since: 1.4.0
    */
   param_spec = g_param_spec_uint("margin-top",
 				 "margin top",
@@ -123,11 +123,11 @@ ags_scrolled_scale_box_class_init(AgsScrolledScaleBoxClass *scrolled_scale_box)
 				  param_spec);
 
   /**
-   * AgsScrolledScaleBox:margin-bottom:
+   * AgsScrolledLevelBox:margin-bottom:
    *
    * The margin bottom.
    * 
-   * Since: 1.3.0
+   * Since: 1.4.0
    */
   param_spec = g_param_spec_uint("margin-bottom",
 				 "margin bottom",
@@ -141,11 +141,11 @@ ags_scrolled_scale_box_class_init(AgsScrolledScaleBoxClass *scrolled_scale_box)
 				  param_spec);
 
   /**
-   * AgsScrolledScaleBox:margin-left:
+   * AgsScrolledLevelBox:margin-left:
    *
    * The margin left.
    * 
-   * Since: 1.3.0
+   * Since: 1.4.0
    */
   param_spec = g_param_spec_uint("margin-left",
 				 "margin left",
@@ -159,11 +159,11 @@ ags_scrolled_scale_box_class_init(AgsScrolledScaleBoxClass *scrolled_scale_box)
 				  param_spec);
 
   /**
-   * AgsScrolledScaleBox:margin-right:
+   * AgsScrolledLevelBox:margin-right:
    *
    * The margin right.
    * 
-   * Since: 1.3.0
+   * Since: 1.4.0
    */
   param_spec = g_param_spec_uint("margin-right",
 				 "margin right",
@@ -177,68 +177,68 @@ ags_scrolled_scale_box_class_init(AgsScrolledScaleBoxClass *scrolled_scale_box)
 				  param_spec);
 
   /* GtkWidgetClass */
-  widget = (GtkWidgetClass *) scrolled_scale_box;
+  widget = (GtkWidgetClass *) scrolled_level_box;
 
-  widget->size_request = ags_scrolled_scale_box_size_request;
-  widget->size_allocate = ags_scrolled_scale_box_size_allocate;
+  widget->size_request = ags_scrolled_level_box_size_request;
+  widget->size_allocate = ags_scrolled_level_box_size_allocate;
 }
 
 void
-ags_scrolled_scale_box_init(AgsScrolledScaleBox *scrolled_scale_box)
+ags_scrolled_level_box_init(AgsScrolledLevelBox *scrolled_level_box)
 {
-  scrolled_scale_box->margin_top = 0;
-  scrolled_scale_box->margin_bottom = 0;
-  scrolled_scale_box->margin_left = 0;
-  scrolled_scale_box->margin_right = 0;
+  scrolled_level_box->margin_top = 0;
+  scrolled_level_box->margin_bottom = 0;
+  scrolled_level_box->margin_left = 0;
+  scrolled_level_box->margin_right = 0;
 
   /* viewport */
-  scrolled_scale_box->viewport = gtk_viewport_new(NULL,
+  scrolled_level_box->viewport = gtk_viewport_new(NULL,
 						  NULL);
-  g_object_set(scrolled_scale_box->viewport,
+  g_object_set(scrolled_level_box->viewport,
 	       "shadow-type", GTK_SHADOW_NONE,
 	       NULL);
-  gtk_container_add(scrolled_scale_box,
-		    scrolled_scale_box->viewport);
+  gtk_container_add(scrolled_level_box,
+		    scrolled_level_box->viewport);
 
-  /* scale box */
-  scrolled_scale_box->scale_box = NULL;
+  /* level box */
+  scrolled_level_box->level_box = NULL;
   
 #if 0
-  scrolled_scale_box->scale_box = ags_vscale_box_new();
-  gtk_container_add(scrolled_scale_box->viewport,
-		    scrolled_scale_box->scale_box);
+  scrolled_level_box->level_box = ags_vlevel_box_new();
+  gtk_container_add(scrolled_level_box->viewport,
+		    scrolled_level_box->level_box);
 #endif
 }
 
 void
-ags_scrolled_scale_box_set_property(GObject *gobject,
+ags_scrolled_level_box_set_property(GObject *gobject,
 				    guint prop_id,
 				    const GValue *value,
 				    GParamSpec *param_spec)
 {
-  AgsScrolledScaleBox *scrolled_scale_box;
+  AgsScrolledLevelBox *scrolled_level_box;
 
-  scrolled_scale_box = AGS_SCROLLED_SCALE_BOX(gobject);
+  scrolled_level_box = AGS_SCROLLED_LEVEL_BOX(gobject);
 
   switch(prop_id){
   case PROP_MARGIN_TOP:
     {
-      scrolled_scale_box->margin_top = g_value_get_uint(value);
+      scrolled_level_box->margin_top = g_value_get_uint(value);
     }
     break;
   case PROP_MARGIN_BOTTOM:
     {
-      scrolled_scale_box->margin_bottom = g_value_get_uint(value);
+      scrolled_level_box->margin_bottom = g_value_get_uint(value);
     }
     break;
   case PROP_MARGIN_LEFT:
     {
-      scrolled_scale_box->margin_left = g_value_get_uint(value);
+      scrolled_level_box->margin_left = g_value_get_uint(value);
     }
     break;
   case PROP_MARGIN_RIGHT:
     {
-      scrolled_scale_box->margin_right = g_value_get_uint(value);
+      scrolled_level_box->margin_right = g_value_get_uint(value);
     }
     break;
   default:
@@ -248,38 +248,38 @@ ags_scrolled_scale_box_set_property(GObject *gobject,
 }
 
 void
-ags_scrolled_scale_box_get_property(GObject *gobject,
+ags_scrolled_level_box_get_property(GObject *gobject,
 				    guint prop_id,
 				    GValue *value,
 				    GParamSpec *param_spec)
 {
-  AgsScrolledScaleBox *scrolled_scale_box;
+  AgsScrolledLevelBox *scrolled_level_box;
 
-  scrolled_scale_box = AGS_SCROLLED_SCALE_BOX(gobject);
+  scrolled_level_box = AGS_SCROLLED_LEVEL_BOX(gobject);
 
   switch(prop_id){
   case PROP_MARGIN_TOP:
     {
       g_value_set_uint(value,
-		       scrolled_scale_box->margin_top);
+		       scrolled_level_box->margin_top);
     }
     break;
   case PROP_MARGIN_BOTTOM:
     {
       g_value_set_uint(value,
-		       scrolled_scale_box->margin_bottom);
+		       scrolled_level_box->margin_bottom);
     }
     break;
   case PROP_MARGIN_LEFT:
     {
       g_value_set_uint(value,
-		       scrolled_scale_box->margin_left);
+		       scrolled_level_box->margin_left);
     }
     break;
   case PROP_MARGIN_RIGHT:
     {
       g_value_set_uint(value,
-		       scrolled_scale_box->margin_right);
+		       scrolled_level_box->margin_right);
     }
     break;  
   default:
@@ -289,29 +289,29 @@ ags_scrolled_scale_box_get_property(GObject *gobject,
 }
 
 void
-ags_scrolled_scale_box_finalize(GObject *gobject)
+ags_scrolled_level_box_finalize(GObject *gobject)
 {
-  AgsScrolledScaleBox *scrolled_scale_box;
+  AgsScrolledLevelBox *scrolled_level_box;
   
-  scrolled_scale_box = AGS_SCROLLED_SCALE_BOX(gobject);
+  scrolled_level_box = AGS_SCROLLED_LEVEL_BOX(gobject);
   
   /* call parent */
-  G_OBJECT_CLASS(ags_scrolled_scale_box_parent_class)->finalize(gobject);
+  G_OBJECT_CLASS(ags_scrolled_level_box_parent_class)->finalize(gobject);
 }
 
 void
-ags_scrolled_scale_box_size_allocate(GtkWidget *widget,
+ags_scrolled_level_box_size_allocate(GtkWidget *widget,
 				     GtkAllocation *allocation)
 {
-  AgsScrolledScaleBox *scrolled_scale_box;
+  AgsScrolledLevelBox *scrolled_level_box;
 
   GtkAllocation child_allocation;
   GtkRequisition child_requisition;
   
-  scrolled_scale_box = AGS_SCROLLED_SCALE_BOX(widget);
+  scrolled_level_box = AGS_SCROLLED_LEVEL_BOX(widget);
 
   /* viewport allocation */
-  gtk_widget_get_child_requisition((GtkWidget *) scrolled_scale_box->viewport,
+  gtk_widget_get_child_requisition((GtkWidget *) scrolled_level_box->viewport,
 				   &child_requisition);
 
   child_allocation.x = allocation->x;
@@ -320,11 +320,11 @@ ags_scrolled_scale_box_size_allocate(GtkWidget *widget,
   child_allocation.width = allocation->width;
   child_allocation.height = allocation->height;
 
-  gtk_widget_size_allocate((GtkWidget *) scrolled_scale_box->viewport,
+  gtk_widget_size_allocate((GtkWidget *) scrolled_level_box->viewport,
 			   &child_allocation);
 
   /* box */
-  gtk_widget_get_child_requisition((GtkWidget *) scrolled_scale_box->scale_box,
+  gtk_widget_get_child_requisition((GtkWidget *) scrolled_level_box->level_box,
 				   &child_requisition);
 
   child_allocation.x = 0;
@@ -333,17 +333,17 @@ ags_scrolled_scale_box_size_allocate(GtkWidget *widget,
   child_allocation.width = allocation->width;
   child_allocation.height = child_requisition.height;
   
-  gtk_widget_size_allocate((GtkWidget *) scrolled_scale_box->scale_box,
+  gtk_widget_size_allocate((GtkWidget *) scrolled_level_box->level_box,
 			   &child_allocation);
 }
 
 void
-ags_scrolled_scale_box_size_request(GtkWidget *widget,
+ags_scrolled_level_box_size_request(GtkWidget *widget,
 				    GtkRequisition *requisition)
 {
   GtkRequisition child_requisition;
 
-  requisition->width = AGS_SCALE_DEFAULT_WIDTH;
+  requisition->width = AGS_LEVEL_DEFAULT_WIDTH;
   requisition->height = -1;
   
   gtk_widget_size_request(gtk_bin_get_child((GtkContainer *) widget),
@@ -351,21 +351,21 @@ ags_scrolled_scale_box_size_request(GtkWidget *widget,
 }
 
 /**
- * ags_scrolled_scale_box_new:
+ * ags_scrolled_level_box_new:
  *
- * Create a new #AgsScrolledScaleBox.
+ * Create a new #AgsScrolledLevelBox.
  *
- * Returns: a new #AgsScrolledScaleBox
+ * Returns: a new #AgsScrolledLevelBox
  *
- * Since: 1.3.0
+ * Since: 1.4.0
  */
-AgsScrolledScaleBox*
-ags_scrolled_scale_box_new()
+AgsScrolledLevelBox*
+ags_scrolled_level_box_new()
 {
-  AgsScrolledScaleBox *scrolled_scale_box;
+  AgsScrolledLevelBox *scrolled_level_box;
 
-  scrolled_scale_box = (AgsScrolledScaleBox *) g_object_new(AGS_TYPE_SCROLLED_SCALE_BOX,
+  scrolled_level_box = (AgsScrolledLevelBox *) g_object_new(AGS_TYPE_SCROLLED_LEVEL_BOX,
 							    NULL);
 
-  return(scrolled_scale_box);
+  return(scrolled_level_box);
 }
diff --git a/ags/widget/ags_scrolled_level_box.h b/ags/widget/ags_scrolled_level_box.h
new file mode 100644
index 0000000..beccf84
--- /dev/null
+++ b/ags/widget/ags_scrolled_level_box.h
@@ -0,0 +1,63 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2017 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_SCROLLED_LEVEL_BOX_H__
+#define __AGS_SCROLLED_LEVEL_BOX_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+#include <ags/widget/ags_level_box.h>
+
+#define AGS_TYPE_SCROLLED_LEVEL_BOX                (ags_scrolled_level_box_get_type())
+#define AGS_SCROLLED_LEVEL_BOX(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_SCROLLED_LEVEL_BOX, AgsScrolledLevelBox))
+#define AGS_SCROLLED_LEVEL_BOX_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_SCROLLED_LEVEL_BOX, AgsScrolledLevelBoxClass))
+#define AGS_IS_SCROLLED_LEVEL_BOX(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AGS_TYPE_SCROLLED_LEVEL_BOX))
+#define AGS_IS_SCROLLED_LEVEL_BOX_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_SCROLLED_LEVEL_BOX))
+#define AGS_SCROLLED_LEVEL_BOX_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS (obj, AGS_TYPE_SCROLLED_LEVEL_BOX, AgsScrolledLevelBoxClass))
+
+typedef struct _AgsScrolledLevelBox AgsScrolledLevelBox;
+typedef struct _AgsScrolledLevelBoxClass AgsScrolledLevelBoxClass;
+
+struct _AgsScrolledLevelBox
+{
+  GtkBin bin;
+
+  guint margin_top;
+  guint margin_bottom;
+  guint margin_left;
+  guint margin_right;
+  
+  GtkViewport *viewport;
+
+  AgsLevelBox *level_box;
+};
+
+struct _AgsScrolledLevelBoxClass
+{
+  GtkBinClass bin;
+};
+
+GType ags_scrolled_level_box_get_type(void);
+
+AgsScrolledLevelBox* ags_scrolled_level_box_new();
+
+#endif /*__AGS_SCROLLED_LEVEL_BOX_H__*/
diff --git a/ags/widget/ags_scrolled_piano.c b/ags/widget/ags_scrolled_piano.c
index ddeda15..17a0e1d 100644
--- a/ags/widget/ags_scrolled_piano.c
+++ b/ags/widget/ags_scrolled_piano.c
@@ -333,7 +333,7 @@ ags_scrolled_piano_size_allocate(GtkWidget *widget,
   }
 
   gtk_widget_size_allocate((GtkWidget *) scrolled_piano->viewport,
-			   allocation);
+			   &child_allocation);
 }
 
 void
diff --git a/ags/widget/ags_vlevel_box.c b/ags/widget/ags_vlevel_box.c
new file mode 100644
index 0000000..7f8009f
--- /dev/null
+++ b/ags/widget/ags_vlevel_box.c
@@ -0,0 +1,91 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2017 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/widget/ags_vlevel_box.h>
+
+void ags_vlevel_box_class_init(AgsVLevelBoxClass *vlevel_box);
+void ags_vlevel_box_init(AgsVLevelBox *vlevel_box);
+
+/**
+ * SECTION:ags_vlevel_box
+ * @short_description: vertical box widget
+ * @title: AgsVLevelBox
+ * @section_id:
+ * @include: ags/widget/ags_vlevel_box.h
+ *
+ * The #AgsVLevelBox is an vertical box widget containing #AgsLevel.
+ */
+
+GType
+ags_vlevel_box_get_type(void)
+{
+  static GType ags_type_vlevel_box = 0;
+
+  if(!ags_type_vlevel_box){
+    static const GTypeInfo ags_vlevel_box_info = {
+      sizeof (AgsVLevelBoxClass),
+      NULL, /* base_init */
+      NULL, /* base_finalize */
+      (GClassInitFunc) ags_vlevel_box_class_init,
+      NULL, /* class_finalize */
+      NULL, /* class_data */
+      sizeof (AgsVLevelBox),
+      0,    /* n_preallocs */
+      (GInstanceInitFunc) ags_vlevel_box_init,
+    };
+
+    ags_type_vlevel_box = g_type_register_static(AGS_TYPE_LEVEL_BOX,
+						 "AgsVLevelBox", &ags_vlevel_box_info,
+						 0);
+  }
+  
+  return(ags_type_vlevel_box);
+}
+
+void
+ags_vlevel_box_class_init(AgsVLevelBoxClass *vlevel_box)
+{
+}
+
+void
+ags_vlevel_box_init(AgsVLevelBox *vlevel_box)
+{
+  gtk_orientable_set_orientation(GTK_ORIENTABLE(vlevel_box),
+				 GTK_ORIENTATION_VERTICAL);
+}
+
+/**
+ * ags_vlevel_box_new:
+ * 
+ * Create a new instance of #AgsVLevelBox.
+ * 
+ * Returns: the new #AgsVLevelBox instance
+ * 
+ * Since: 1.4.0
+ */
+AgsVLevelBox*
+ags_vlevel_box_new()
+{
+  AgsVLevelBox *vlevel_box;
+
+  vlevel_box = (AgsVLevelBox *) g_object_new(AGS_TYPE_VLEVEL_BOX,
+					     NULL);
+  
+  return(vlevel_box);
+}
diff --git a/ags/widget/ags_vlevel_box.h b/ags/widget/ags_vlevel_box.h
new file mode 100644
index 0000000..6778e98
--- /dev/null
+++ b/ags/widget/ags_vlevel_box.h
@@ -0,0 +1,54 @@
+/* GSequencer - Advanced GTK Sequencer
+ * Copyright (C) 2005-2017 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_VLEVEL_BOX_H__
+#define __AGS_VLEVEL_BOX_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+#include <ags/widget/ags_level_box.h>
+
+#define AGS_TYPE_VLEVEL_BOX                (ags_vlevel_box_get_type())
+#define AGS_VLEVEL_BOX(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_VLEVEL_BOX, AgsVLevelBox))
+#define AGS_VLEVEL_BOX_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST((class), AGS_TYPE_VLEVEL_BOX, AgsVLevelBoxClass))
+#define AGS_IS_VLEVEL_BOX(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AGS_TYPE_VLEVEL_BOX))
+#define AGS_IS_VLEVEL_BOX_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_VLEVEL_BOX))
+#define AGS_VLEVEL_BOX_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS (obj, AGS_TYPE_VLEVEL_BOX, AgsVLevelBoxClass))
+
+typedef struct _AgsVLevelBox AgsVLevelBox;
+typedef struct _AgsVLevelBoxClass AgsVLevelBoxClass;
+
+struct _AgsVLevelBox
+{
+  AgsLevelBox level_box;
+};
+
+struct _AgsVLevelBoxClass
+{
+  AgsLevelBoxClass level_box;
+};
+
+GType ags_vlevel_box_get_type(void);
+
+AgsVLevelBox* ags_vlevel_box_new();
+
+#endif /*__AGS_VLEVEL_BOX_H__*/
diff --git a/ags/widget/ags_waveform.c b/ags/widget/ags_waveform.c
index e3cf2b5..65bc791 100644
--- a/ags/widget/ags_waveform.c
+++ b/ags/widget/ags_waveform.c
@@ -44,7 +44,7 @@ ags_waveform_get_type(void)
     };
 
     ags_type_waveform = g_type_register_static(GTK_TYPE_WIDGET,
-					       "AgsWaveform\0", &ags_waveform_info,
+					       "AgsWaveform", &ags_waveform_info,
 					       0);
   }
 
@@ -63,7 +63,7 @@ void
 ags_waveform_init(AgsWaveform *waveform)
 {
   g_object_set(G_OBJECT(waveform),
-	       "app-paintable\0", TRUE,
+	       "app-paintable", TRUE,
 	       NULL);
 }
 
diff --git a/ags/widget/ags_waveform.h b/ags/widget/ags_waveform.h
index 8c618d4..7c3e3c7 100644
--- a/ags/widget/ags_waveform.h
+++ b/ags/widget/ags_waveform.h
@@ -22,6 +22,7 @@
 
 #include <glib.h>
 #include <glib-object.h>
+
 #include <gtk/gtk.h>
 
 #define AGS_TYPE_WAVEFORM                (ags_waveform_get_type())
diff --git a/configure b/configure
index 1403227..c791c98 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for gsequencer 1.3.3.
+# Generated by GNU Autoconf 2.69 for gsequencer 1.4.5.
 #
 # Report bugs to <jkraehemann-guest at users.alioth.debian.org>.
 #
@@ -590,8 +590,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='gsequencer'
 PACKAGE_TARNAME='gsequencer'
-PACKAGE_VERSION='1.3.3'
-PACKAGE_STRING='gsequencer 1.3.3'
+PACKAGE_VERSION='1.4.5'
+PACKAGE_STRING='gsequencer 1.4.5'
 PACKAGE_BUGREPORT='jkraehemann-guest at users.alioth.debian.org'
 PACKAGE_URL=''
 
@@ -1473,7 +1473,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures gsequencer 1.3.3 to adapt to many kinds of systems.
+\`configure' configures gsequencer 1.4.5 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1548,7 +1548,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of gsequencer 1.3.3:";;
+     short | recursive ) echo "Configuration of gsequencer 1.4.5:";;
    esac
   cat <<\_ACEOF
 
@@ -1741,7 +1741,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-gsequencer configure 1.3.3
+gsequencer configure 1.4.5
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2218,7 +2218,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by gsequencer $as_me 1.3.3, which was
+It was created by gsequencer $as_me 1.4.5, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3085,7 +3085,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='gsequencer'
- VERSION='1.3.3'
+ VERSION='1.4.5'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -19597,7 +19597,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by gsequencer $as_me 1.3.3, which was
+This file was extended by gsequencer $as_me 1.4.5, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -19663,7 +19663,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-gsequencer config.status 1.3.3
+gsequencer config.status 1.4.5
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
index f2d14e1..1cd326c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,7 +6,7 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ([2.69])
-AC_INIT([gsequencer],[1.3.3],[jkraehemann-guest at users.alioth.debian.org])
+AC_INIT([gsequencer],[1.4.5],[jkraehemann-guest at users.alioth.debian.org])
 AM_INIT_AUTOMAKE([subdir-objects])
 AC_CONFIG_SRCDIR([ags/config.h.in])
 AC_CONFIG_HEADERS([ags/config.h])
diff --git a/docs/reference/libags-audio/libags_audio-sections.txt b/docs/reference/libags-audio/libags_audio-sections.txt
index 6cf3c3c..ff49be7 100644
--- a/docs/reference/libags-audio/libags_audio-sections.txt
+++ b/docs/reference/libags-audio/libags_audio-sections.txt
@@ -309,6 +309,8 @@ ags_audio_add_notation
 ags_audio_remove_notation
 ags_audio_add_automation
 ags_audio_remove_automation
+ags_audio_add_wave
+ags_audio_remove_wave
 ags_audio_add_recall_id
 ags_audio_remove_recall_id
 ags_audio_add_recycling_context
@@ -328,6 +330,7 @@ ags_audio_done
 ags_audio_cancel
 ags_audio_remove
 ags_audio_find_port
+ags_audio_find_port_by_specifier_and_scope
 ags_audio_open_files
 ags_audio_recursive_set_property
 ags_audio_recursive_play_init
@@ -657,6 +660,8 @@ ags_audio_signal_stream_resize
 ags_audio_signal_stream_safe_resize
 ags_audio_signal_realloc_buffer_size
 ags_audio_signal_duplicate_stream
+ags_audio_signal_add_note
+ags_audio_signal_remove_note
 ags_audio_signal_get_template
 ags_audio_signal_get_stream_current
 ags_audio_signal_get_by_recall_id
@@ -718,14 +723,22 @@ ags_audio_xml_serialization_factory_get_type
 AGS_AUTOMATION_DEFAULT_BPM
 AGS_AUTOMATION_TICS_PER_BEAT
 AGS_AUTOMATION_MINIMUM_ACCELERATION_LENGTH
+AGS_AUTOMATION_MAXIMUM_ACCELERATION_LENGTH
 AGS_AUTOMATION_DEFAULT_LENGTH
 AGS_AUTOMATION_DEFAULT_JIFFIE
 AGS_AUTOMATION_DEFAULT_DURATION
+AGS_AUTOMATION_DEFAULT_OFFSET
 AGS_AUTOMATION_DEFAULT_PRECISION
 AGS_AUTOMATION_MAXIMUM_STEPS
+AGS_AUTOMATION_CLIPBOARD_VERSION
+AGS_AUTOMATION_CLIPBOARD_TYPE
+AGS_AUTOMATION_CLIPBOARD_FORMAT
+AGS_AUTOMATION_CLIPBOARD_LEGACY_FORMAT
 AgsAutomationFlags
 ags_automation_find_port
 ags_automation_find_near_timestamp
+ags_automation_find_near_timestamp_extended
+ags_automation_add
 ags_automation_add_acceleration
 ags_automation_remove_acceleration_at_position
 ags_automation_get_selection
@@ -742,9 +755,12 @@ ags_automation_copy_selection
 ags_automation_cut_selection
 ags_automation_merge_clipboard
 ags_automation_insert_from_clipboard
+ags_automation_insert_from_clipboard_extended
 ags_automation_get_current
 ags_automation_get_specifier_unique
+ags_automation_get_specifier_unique_with_channel_type
 ags_automation_find_specifier
+ags_automation_find_channel_type_with_control_name
 ags_automation_find_specifier_with_type_and_line
 ags_automation_get_value
 ags_automation_new
@@ -793,6 +809,27 @@ ags_base_plugin_get_type
 </SECTION>
 
 <SECTION>
+<FILE>ags_buffer</FILE>
+<TITLE>AgsBuffer</TITLE>
+AgsBufferFlags
+ags_buffer_set_samplerate
+ags_buffer_set_buffer_size
+ags_buffer_set_format
+ags_buffer_sort_func
+ags_buffer_duplicate
+ags_buffer_new
+<SUBSECTION Public>
+AGS_BUFFER
+AGS_BUFFER_CLASS
+AGS_BUFFER_GET_CLASS
+AGS_IS_BUFFER
+AGS_TYPE_BUFFER
+AgsBuffer
+AgsBufferClass
+ags_buffer_get_type
+</SECTION>
+
+<SECTION>
 <FILE>ags_buffer_audio_signal</FILE>
 <TITLE>AgsBufferAudioSignal</TITLE>
 ags_buffer_audio_signal_new
@@ -898,6 +935,36 @@ ags_cancel_recall_get_type
 </SECTION>
 
 <SECTION>
+<FILE>ags_capture_sound_audio</FILE>
+<TITLE>AgsCaptureSoundAudio</TITLE>
+ags_capture_sound_audio_new
+<SUBSECTION Public>
+AGS_CAPTURE_SOUND_AUDIO
+AGS_CAPTURE_SOUND_AUDIO_CLASS
+AGS_CAPTURE_SOUND_AUDIO_GET_CLASS
+AGS_IS_CAPTURE_SOUND_AUDIO
+AGS_TYPE_CAPTURE_SOUND_AUDIO
+AgsCaptureSoundAudio
+AgsCaptureSoundAudioClass
+ags_capture_sound_audio_get_type
+</SECTION>
+
+<SECTION>
+<FILE>ags_capture_sound_audio_run</FILE>
+<TITLE>AgsCaptureSoundAudioRun</TITLE>
+ags_capture_sound_audio_run_new
+<SUBSECTION Public>
+AGS_CAPTURE_SOUND_AUDIO_RUN
+AGS_CAPTURE_SOUND_AUDIO_RUN_CLASS
+AGS_CAPTURE_SOUND_AUDIO_RUN_GET_CLASS
+AGS_IS_CAPTURE_SOUND_AUDIO_RUN
+AGS_TYPE_CAPTURE_SOUND_AUDIO_RUN
+AgsCaptureSoundAudioRun
+AgsCaptureSoundAudioRunClass
+ags_capture_sound_audio_run_get_type
+</SECTION>
+
+<SECTION>
 <FILE>ags_change_soundcard</FILE>
 <TITLE>AgsChangeSoundcard</TITLE>
 ags_change_soundcard_new
@@ -957,6 +1024,7 @@ ags_channel_cancel
 ags_channel_remove
 ags_channel_recall_id_set
 ags_channel_find_port
+ags_channel_find_port_by_specifier_and_scope
 ags_channel_set_link
 ags_channel_set_recycling
 ags_channel_recursive_reset_recycling_context
@@ -967,6 +1035,11 @@ ags_channel_recursive_play_threaded
 ags_channel_recursive_play
 ags_channel_tillrecycling_cancel
 ags_channel_recursive_reset_recall_ids
+ags_channel_get_level
+ags_channel_recursive_reset_recall_id
+ags_channel_recursive_init
+ags_channel_recursive_run
+ags_channel_recursive_cancel
 ags_channel_new
 <SUBSECTION Public>
 AGS_CHANNEL
@@ -982,11 +1055,13 @@ ags_channel_get_type
 <SECTION>
 <FILE>ags_channel_iter</FILE>
 AgsChannelIterFlags
+AgsChannelIterMode
 AgsChannelIter
 ags_channel_iter_alloc
 ags_channel_iter_free
 ags_channel_iter_prev
 ags_channel_iter_next
+ags_channel_iter_init
 </SECTION>
 
 <SECTION>
@@ -2756,6 +2831,7 @@ ags_notation_remove_region_from_selection
 ags_notation_copy_selection
 ags_notation_cut_selection
 ags_notation_insert_from_clipboard
+ags_notation_insert_from_clipboard_extended
 ags_notation_get_current
 ags_notation_to_raw_midi
 ags_notation_from_raw_midi
@@ -3556,6 +3632,7 @@ ags_recall_child_added
 ags_recall_run_init_pre
 ags_recall_run_init_inter
 ags_recall_run_init_post
+ags_recall_check_rt_stream
 ags_recall_automate
 ags_recall_run_pre
 ags_recall_run_inter
@@ -4335,6 +4412,66 @@ ags_route_lv2_audio_run_get_type
 </SECTION>
 
 <SECTION>
+<FILE>ags_rt_stream_audio_signal</FILE>
+<TITLE>AgsRtStreamAudioSignal</TITLE>
+ags_rt_stream_audio_signal_new
+<SUBSECTION Public>
+AGS_IS_RT_STREAM_AUDIO_SIGNAL
+AGS_RT_STREAM_AUDIO_SIGNAL
+AGS_RT_STREAM_AUDIO_SIGNAL_CLASS
+AGS_RT_STREAM_AUDIO_SIGNAL_GET_CLASS
+AGS_TYPE_RT_STREAM_AUDIO_SIGNAL
+AgsRtStreamAudioSignal
+AgsRtStreamAudioSignalClass
+ags_rt_stream_audio_signal_get_type
+</SECTION>
+
+<SECTION>
+<FILE>ags_rt_stream_channel</FILE>
+<TITLE>AgsRtStreamChannel</TITLE>
+ags_rt_stream_channel_new
+<SUBSECTION Public>
+AGS_IS_RT_STREAM_CHANNEL
+AGS_RT_STREAM_CHANNEL
+AGS_RT_STREAM_CHANNEL_CLASS
+AGS_RT_STREAM_CHANNEL_GET_CLASS
+AGS_TYPE_RT_STREAM_CHANNEL
+AgsRtStreamChannel
+AgsRtStreamChannelClass
+ags_rt_stream_channel_get_type
+</SECTION>
+
+<SECTION>
+<FILE>ags_rt_stream_channel_run</FILE>
+<TITLE>AgsRtStreamChannelRun</TITLE>
+ags_rt_stream_channel_run_new
+<SUBSECTION Public>
+AGS_IS_RT_STREAM_CHANNEL_RUN
+AGS_RT_STREAM_CHANNEL_RUN
+AGS_RT_STREAM_CHANNEL_RUN_CLASS
+AGS_RT_STREAM_CHANNEL_RUN_GET_CLASS
+AGS_TYPE_RT_STREAM_CHANNEL_RUN
+AgsRtStreamChannelRun
+AgsRtStreamChannelRunClass
+ags_rt_stream_channel_run_get_type
+</SECTION>
+
+<SECTION>
+<FILE>ags_rt_stream_recycling</FILE>
+<TITLE>AgsRtStreamRecycling</TITLE>
+ags_rt_stream_recycling_new
+<SUBSECTION Public>
+AGS_IS_RT_STREAM_RECYCLING
+AGS_RT_STREAM_RECYCLING
+AGS_RT_STREAM_RECYCLING_CLASS
+AGS_RT_STREAM_RECYCLING_GET_CLASS
+AGS_TYPE_RT_STREAM_RECYCLING
+AgsRtStreamRecycling
+AgsRtStreamRecyclingClass
+ags_rt_stream_recycling_get_type
+</SECTION>
+
+<SECTION>
 <FILE>ags_save_file</FILE>
 <TITLE>AgsSaveFile</TITLE>
 ags_save_file_new
@@ -4818,3 +4955,47 @@ AgsVolumeRecyclingClass
 ags_volume_recycling_get_type
 </SECTION>
 
+<SECTION>
+<FILE>ags_wave</FILE>
+<TITLE>AgsWave</TITLE>
+AGS_WAVE_DEFAULT_BPM
+AGS_WAVE_TICS_PER_BEAT
+AGS_WAVE_MINIMUM_BUFFER_LENGTH
+AGS_WAVE_DEFAULT_LENGTH
+AGS_WAVE_DEFAULT_JIFFIE
+AGS_WAVE_DEFAULT_DURATION
+AGS_WAVE_DEFAULT_OFFSET
+AGS_WAVE_CLIPBOARD_VERSION
+AGS_WAVE_CLIPBOARD_TYPE
+AGS_WAVE_CLIPBOARD_FORMAT
+AgsWaveFlags
+ags_wave_set_samplerate
+ags_wave_set_buffer_size
+ags_wave_set_format
+ags_wave_find_near_timestamp
+ags_wave_add
+ags_wave_add_buffer
+ags_wave_remove_buffer
+ags_wave_get_selection
+ags_wave_is_buffer_selected
+ags_wave_find_region
+ags_wave_free_selection
+ags_wave_add_region_to_selection
+ags_wave_remove_region_from_selection
+ags_wave_add_all_to_selection
+ags_wave_copy_selection
+ags_wave_cut_selection
+ags_wave_insert_from_clipboard
+ags_wave_insert_from_clipboard_extended
+ags_wave_new
+<SUBSECTION Public>
+AGS_IS_WAVE
+AGS_TYPE_WAVE
+AGS_WAVE
+AGS_WAVE_CLASS
+AGS_WAVE_GET_CLASS
+AgsWave
+AgsWaveClass
+ags_wave_get_type
+</SECTION>
+
diff --git a/docs/reference/libags-audio/libags_audio.interfaces b/docs/reference/libags-audio/libags_audio.interfaces
index 4b930e4..ddcb267 100644
--- a/docs/reference/libags-audio/libags_audio.interfaces
+++ b/docs/reference/libags-audio/libags_audio.interfaces
@@ -94,6 +94,7 @@ AgsPrepareAudioSignal AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsRecallDssiRun AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsRecallLadspaRun AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsRecallLv2Run AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
+AgsRtStreamAudioSignal AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsStreamAudioSignal AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsVolumeAudioSignal AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsRecallChannel AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
@@ -110,6 +111,7 @@ AgsPrepareChannel AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsRecallDssi AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsRecallLadspa AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsRecallLv2 AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
+AgsRtStreamChannel AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsStreamChannel AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsVolumeChannel AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsRecallChannelRun AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
@@ -125,6 +127,7 @@ AgsPlayChannelRun AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsPlayChannelRunMaster AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsPrepareChannelRun AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsRecallChannelRunDummy AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
+AgsRtStreamChannelRun AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsStreamChannelRun AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsVolumeChannelRun AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsRecallRecycling AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
@@ -137,9 +140,11 @@ AgsPeakRecycling AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsPlayRecycling AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsPrepareRecycling AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsRecallRecyclingDummy AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
+AgsRtStreamRecycling AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsStreamRecycling AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsVolumeRecycling AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsRecallAudio AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
+AgsCaptureSoundAudio AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsCopyNotationAudio AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsCopyPatternAudio AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsCountBeatsAudio AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin AgsTactable
@@ -153,6 +158,7 @@ AgsRecordMidiAudio AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsRouteDssiAudio AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsRouteLv2Audio AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsRecallAudioRun AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
+AgsCaptureSoundAudioRun AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsCopyNotationAudioRun AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsCopyPatternAudioRun AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsCountBeatsAudioRun AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin AgsCountable AgsSeekable AgsTactable
@@ -167,6 +173,7 @@ AgsRouteDssiAudioRun AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsRouteLv2AudioRun AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsPlayAudioFile AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
 AgsPlayNote AgsConnectable AgsPackable AgsDynamicConnectable AgsPlugin
+AgsBuffer AgsConnectable
 AgsChannel AgsConnectable
 AgsInput AgsConnectable
 AgsOutput AgsConnectable
@@ -217,4 +224,5 @@ AgsRemoteChannel AgsConnectable
 AgsRemoteInput AgsConnectable
 AgsRemoteOutput AgsConnectable
 AgsSndfile AgsConnectable AgsPlayable
+AgsWave AgsConnectable
 AgsRegistry AgsConnectable
diff --git a/docs/reference/libags-audio/libags_audio.types b/docs/reference/libags-audio/libags_audio.types
index 62d0e20..62aa62f 100644
--- a/docs/reference/libags-audio/libags_audio.types
+++ b/docs/reference/libags-audio/libags_audio.types
@@ -31,10 +31,13 @@ ags_base_plugin_get_type
 ags_buffer_audio_signal_get_type
 ags_buffer_channel_get_type
 ags_buffer_channel_run_get_type
+ags_buffer_get_type
 ags_buffer_recycling_get_type
 ags_cancel_audio_get_type
 ags_cancel_channel_get_type
 ags_cancel_recall_get_type
+ags_capture_sound_audio_get_type
+ags_capture_sound_audio_run_get_type
 ags_change_soundcard_get_type
 ags_channel_get_type
 ags_channel_thread_get_type
@@ -204,6 +207,10 @@ ags_route_dssi_audio_get_type
 ags_route_dssi_audio_run_get_type
 ags_route_lv2_audio_get_type
 ags_route_lv2_audio_run_get_type
+ags_rt_stream_audio_signal_get_type
+ags_rt_stream_channel_get_type
+ags_rt_stream_channel_run_get_type
+ags_rt_stream_recycling_get_type
 ags_save_file_get_type
 ags_seek_soundcard_get_type
 ags_sequencer_thread_get_type
@@ -232,3 +239,4 @@ ags_volume_audio_signal_get_type
 ags_volume_channel_get_type
 ags_volume_channel_run_get_type
 ags_volume_recycling_get_type
+ags_wave_get_type
diff --git a/docs/reference/libags-audio/libags_audio.xml b/docs/reference/libags-audio/libags_audio.xml
index ffb9b98..b469509 100644
--- a/docs/reference/libags-audio/libags_audio.xml
+++ b/docs/reference/libags-audio/libags_audio.xml
@@ -60,6 +60,7 @@
     <xi:include href="xml/ags_audio_connection.xml"/>
     <xi:include href="xml/ags_audio_signal.xml"/>
     <xi:include href="xml/ags_automation.xml"/>
+    <xi:include href="xml/ags_buffer.xml"/>
     <xi:include href="xml/ags_channel.xml"/>
     <xi:include href="xml/ags_channel_iter.xml"/>
     <xi:include href="xml/ags_fifoout.xml"/>
@@ -100,6 +101,7 @@
     <xi:include href="xml/ags_sound_provider.xml"/>
     <xi:include href="xml/ags_synth_generator.xml"/>
     <xi:include href="xml/ags_synth_util.xml"/>
+    <xi:include href="xml/ags_wave.xml"/>
 
     <chapter id="audio-thread">
       <title>Audio thread - multi-threaded audio</title>
@@ -175,6 +177,8 @@
       <xi:include href="xml/ags_buffer_channel.xml"/>
       <xi:include href="xml/ags_buffer_channel_run.xml"/>
       <xi:include href="xml/ags_buffer_recycling.xml"/>
+      <xi:include href="xml/ags_capture_sound_audio.xml"/>
+      <xi:include href="xml/ags_capture_sound_audio_run.xml"/>
       <xi:include href="xml/ags_copy_audio_signal.xml"/>
       <xi:include href="xml/ags_copy_channel.xml"/>
       <xi:include href="xml/ags_copy_channel_run.xml"/>
@@ -233,6 +237,10 @@
       <xi:include href="xml/ags_route_dssi_audio_run.xml"/>
       <xi:include href="xml/ags_route_lv2_audio.xml"/>
       <xi:include href="xml/ags_route_lv2_audio_run.xml"/>
+      <xi:include href="xml/ags_rt_stream_audio_signal.xml"/>
+      <xi:include href="xml/ags_rt_stream_channel.xml"/>
+      <xi:include href="xml/ags_rt_stream_channel_run.xml"/>
+      <xi:include href="xml/ags_rt_stream_recycling.xml"/>
       <xi:include href="xml/ags_stream_audio_signal.xml"/>
       <xi:include href="xml/ags_stream_channel.xml"/>
       <xi:include href="xml/ags_stream_channel_run.xml"/>
diff --git a/docs/reference/libags-gui/libags_gui-sections.txt b/docs/reference/libags-gui/libags_gui-sections.txt
index b8d36bf..f8f6afc 100644
--- a/docs/reference/libags-gui/libags_gui-sections.txt
+++ b/docs/reference/libags-gui/libags_gui-sections.txt
@@ -163,6 +163,21 @@ ags_hled_array_get_type
 </SECTION>
 
 <SECTION>
+<FILE>ags_hlevel_box</FILE>
+<TITLE>AgsHLevelBox</TITLE>
+ags_hlevel_box_new
+<SUBSECTION Public>
+AGS_HLEVEL_BOX
+AGS_HLEVEL_BOX_CLASS
+AGS_HLEVEL_BOX_GET_CLASS
+AGS_IS_HLEVEL_BOX
+AGS_TYPE_HLEVEL_BOX
+AgsHLevelBox
+AgsHLevelBoxClass
+ags_hlevel_box_get_type
+</SECTION>
+
+<SECTION>
 <FILE>ags_hscale_box</FILE>
 <TITLE>AgsHScaleBox</TITLE>
 ags_hscale_box_new
@@ -246,6 +261,52 @@ ags_led_array_get_type
 </SECTION>
 
 <SECTION>
+<FILE>ags_level</FILE>
+<TITLE>AgsLevel</TITLE>
+AGS_LEVEL_DEFAULT_WIDTH
+AGS_LEVEL_DEFAULT_HEIGHT
+AGS_LEVEL_DEFAULT_LOWER
+AGS_LEVEL_DEFAULT_UPPER
+AGS_LEVEL_DEFAULT_NORMALIZED_VOLUME
+AGS_LEVEL_DEFAULT_STEP_COUNT
+AGS_LEVEL_DEFAULT_PAGE_SIZE
+AGS_LEVEL_DEFAULT_SAMPLERATE
+AgsLevelFlags
+AgsLevelButtonState
+AgsLevelKeyMask
+AgsLevelLayout
+AgsLevelAction
+ags_level_new
+<SUBSECTION Public>
+AGS_IS_LEVEL
+AGS_LEVEL
+AGS_LEVEL_CLASS
+AGS_LEVEL_GET_CLASS
+AGS_TYPE_LEVEL
+AgsLevel
+AgsLevelClass
+ags_level_get_type
+</SECTION>
+
+<SECTION>
+<FILE>ags_level_box</FILE>
+<TITLE>AgsLevelBox</TITLE>
+AGS_LEVEL_BOX_DEFAULT_FIXED_LEVEL_WIDTH
+AGS_LEVEL_BOX_DEFAULT_FIXED_LEVEL_HEIGHT
+AgsLevelBoxFlags
+ags_level_box_new
+<SUBSECTION Public>
+AGS_IS_LEVEL_BOX
+AGS_LEVEL_BOX
+AGS_LEVEL_BOX_CLASS
+AGS_LEVEL_BOX_GET_CLASS
+AGS_TYPE_LEVEL_BOX
+AgsLevelBox
+AgsLevelBoxClass
+ags_level_box_get_type
+</SECTION>
+
+<SECTION>
 <FILE>ags_notebook</FILE>
 <TITLE>AgsNotebook</TITLE>
 AGS_NOTEBOOK_TAB
@@ -477,6 +538,7 @@ AgsScaleButtonState
 AgsScaleKeyMask
 AgsScaleLayout
 AgsScaleAction
+ags_scale_value_changed
 ags_scale_new
 <SUBSECTION Public>
 AGS_IS_SCALE
@@ -508,6 +570,21 @@ ags_scale_box_get_type
 </SECTION>
 
 <SECTION>
+<FILE>ags_scrolled_level_box</FILE>
+<TITLE>AgsScrolledLevelBox</TITLE>
+ags_scrolled_level_box_new
+<SUBSECTION Public>
+AGS_IS_SCROLLED_LEVEL_BOX
+AGS_SCROLLED_LEVEL_BOX
+AGS_SCROLLED_LEVEL_BOX_CLASS
+AGS_SCROLLED_LEVEL_BOX_GET_CLASS
+AGS_TYPE_SCROLLED_LEVEL_BOX
+AgsScrolledLevelBox
+AgsScrolledLevelBoxClass
+ags_scrolled_level_box_get_type
+</SECTION>
+
+<SECTION>
 <FILE>ags_scrolled_piano</FILE>
 <TITLE>AgsScrolledPiano</TITLE>
 ags_scrolled_piano_new
@@ -597,6 +674,21 @@ ags_vled_array_get_type
 </SECTION>
 
 <SECTION>
+<FILE>ags_vlevel_box</FILE>
+<TITLE>AgsVLevelBox</TITLE>
+ags_vlevel_box_new
+<SUBSECTION Public>
+AGS_IS_VLEVEL_BOX
+AGS_TYPE_VLEVEL_BOX
+AGS_VLEVEL_BOX
+AGS_VLEVEL_BOX_CLASS
+AGS_VLEVEL_BOX_GET_CLASS
+AgsVLevelBox
+AgsVLevelBoxClass
+ags_vlevel_box_get_type
+</SECTION>
+
+<SECTION>
 <FILE>ags_vscale_box</FILE>
 <TITLE>AgsVScaleBox</TITLE>
 ags_vscale_box_new
diff --git a/docs/reference/libags-gui/libags_gui.interfaces b/docs/reference/libags-gui/libags_gui.interfaces
index 07361f8..ea7afee 100644
--- a/docs/reference/libags-gui/libags_gui.interfaces
+++ b/docs/reference/libags-gui/libags_gui.interfaces
@@ -10,12 +10,16 @@ AgsLedArray AtkImplementorIface GtkBuildable
 AgsHLedArray AtkImplementorIface GtkBuildable
 AgsVLedArray AtkImplementorIface GtkBuildable
 AgsLed AtkImplementorIface GtkBuildable
+AgsScrolledLevelBox AtkImplementorIface GtkBuildable
 AgsScrolledPiano AtkImplementorIface GtkBuildable
 AgsScrolledScaleBox AtkImplementorIface GtkBuildable
 GtkTable AtkImplementorIface GtkBuildable
 AgsExpanderSet AtkImplementorIface GtkBuildable
 AgsTable AtkImplementorIface GtkBuildable
 GtkBox AtkImplementorIface GtkBuildable GtkOrientable
+AgsLevelBox AtkImplementorIface GtkBuildable GtkOrientable
+AgsHLevelBox AtkImplementorIface GtkBuildable GtkOrientable
+AgsVLevelBox AtkImplementorIface GtkBuildable GtkOrientable
 AgsScaleBox AtkImplementorIface GtkBuildable GtkOrientable
 AgsHScaleBox AtkImplementorIface GtkBuildable GtkOrientable
 AgsVScaleBox AtkImplementorIface GtkBuildable GtkOrientable
@@ -24,6 +28,7 @@ AgsNotebook AtkImplementorIface GtkBuildable GtkOrientable
 AgsIndicator AtkImplementorIface GtkBuildable
 AgsHIndicator AtkImplementorIface GtkBuildable
 AgsVIndicator AtkImplementorIface GtkBuildable
+AgsLevel AtkImplementorIface GtkBuildable
 AgsPiano AtkImplementorIface GtkBuildable
 AgsRuler AtkImplementorIface GtkBuildable
 AgsScale AtkImplementorIface GtkBuildable
diff --git a/docs/reference/libags-gui/libags_gui.types b/docs/reference/libags-gui/libags_gui.types
index f08e3b7..ce48de6 100644
--- a/docs/reference/libags-gui/libags_gui.types
+++ b/docs/reference/libags-gui/libags_gui.types
@@ -4,19 +4,24 @@ ags_expander_get_type
 ags_expander_set_get_type
 ags_hindicator_get_type
 ags_hled_array_get_type
+ags_hlevel_box_get_type
 ags_hscale_box_get_type
 ags_indicator_get_type
 ags_led_array_get_type
 ags_led_get_type
+ags_level_box_get_type
+ags_level_get_type
 ags_notebook_get_type
 ags_piano_get_type
 ags_ruler_get_type
 ags_scale_box_get_type
 ags_scale_get_type
+ags_scrolled_level_box_get_type
 ags_scrolled_piano_get_type
 ags_scrolled_scale_box_get_type
 ags_table_get_type
 ags_vindicator_get_type
 ags_vled_array_get_type
+ags_vlevel_box_get_type
 ags_vscale_box_get_type
 ags_waveform_get_type
diff --git a/docs/reference/libags-gui/libags_gui.xml b/docs/reference/libags-gui/libags_gui.xml
index e6ce5f5..49085e1 100644
--- a/docs/reference/libags-gui/libags_gui.xml
+++ b/docs/reference/libags-gui/libags_gui.xml
@@ -30,6 +30,11 @@
     <xi:include href="xml/ags_led_array.xml"/>
     <xi:include href="xml/ags_hled_array.xml"/>
     <xi:include href="xml/ags_vled_array.xml"/>
+    <xi:include href="xml/ags_level.xml"/>
+    <xi:include href="xml/ags_level_box.xml"/>
+    <xi:include href="xml/ags_vlevel_box.xml"/>
+    <xi:include href="xml/ags_hlevel_box.xml"/>
+    <xi:include href="xml/ags_scrolled_level_box.xml"/>
     <xi:include href="xml/ags_notebook.xml"/>
     <xi:include href="xml/ags_piano.xml"/>
     <xi:include href="xml/ags_scrolled_piano.xml"/>
diff --git a/docs/reference/libags/libags-sections.txt b/docs/reference/libags/libags-sections.txt
index 92acb76..406439c 100644
--- a/docs/reference/libags/libags-sections.txt
+++ b/docs/reference/libags/libags-sections.txt
@@ -57,6 +57,8 @@ ags_async_queue_set_run_cond
 ags_async_queue_get_run_cond
 ags_async_queue_set_run
 ags_async_queue_is_run
+ags_async_queue_schedule_task
+ags_async_queue_schedule_task_list
 <SUBSECTION Public>
 AGS_ASYNC_QUEUE
 AGS_ASYNC_QUEUE_GET_INTERFACE
@@ -130,6 +132,20 @@ ags_autosave_thread_get_type
 </SECTION>
 
 <SECTION>
+<FILE>ags_buffer_util</FILE>
+ags_buffer_util_s8_to_char_buffer
+ags_buffer_util_s16_to_char_buffer
+ags_buffer_util_s24_to_char_buffer
+ags_buffer_util_s32_to_char_buffer
+ags_buffer_util_s64_to_char_buffer
+ags_buffer_util_char_buffer_to_s8
+ags_buffer_util_char_buffer_to_s16
+ags_buffer_util_char_buffer_to_s24
+ags_buffer_util_char_buffer_to_s32
+ags_buffer_util_char_buffer_to_s64
+</SECTION>
+
+<SECTION>
 <FILE>ags_business_group</FILE>
 <TITLE>AgsBusinessGroup</TITLE>
 ags_business_group_set_business_group_name
diff --git a/docs/reference/libags/libags.xml b/docs/reference/libags/libags.xml
index cd43730..bbce297 100644
--- a/docs/reference/libags/libags.xml
+++ b/docs/reference/libags/libags.xml
@@ -27,6 +27,7 @@
   <part id="lib">
     <title>Library - Completion routines</title>
 
+    <xi:include href="xml/ags_buffer_util.xml"/>
     <xi:include href="xml/ags_complex.xml"/>
     <xi:include href="xml/ags_conversion.xml"/>
     <xi:include href="xml/ags_endian.xml"/>
diff --git a/docs/reference/libgsequencer/libgsequencer-sections.txt b/docs/reference/libgsequencer/libgsequencer-sections.txt
index 5b65c22..a292eb3 100644
--- a/docs/reference/libgsequencer/libgsequencer-sections.txt
+++ b/docs/reference/libgsequencer/libgsequencer-sections.txt
@@ -88,6 +88,7 @@ ags_audio_preferences_stop_jack_callback
 <SECTION>
 <FILE>ags_audiorec</FILE>
 <TITLE>AgsAudiorec</TITLE>
+ags_audiorec_open_filename
 ags_audiorec_new
 <SUBSECTION Public>
 AGS_AUDIOREC
@@ -102,7 +103,10 @@ ags_audiorec_get_type
 
 <SECTION>
 <FILE>ags_audiorec_callbacks</FILE>
-
+ags_audiorec_open_callback
+ags_audiorec_keep_data_callback
+ags_audiorec_replace_data_callback
+ags_audiorec_mix_data_callback
 </SECTION>
 
 <SECTION>
@@ -129,6 +133,7 @@ AGS_AUTOMATION_EDIT_DEFAULT_VALUE
 AGS_AUTOMATION_EDIT_DEFAULT_PADDING
 AgsAutomationEditFlags
 AgsAutomationEditMode
+AgsAutomationEditButtonMask
 AgsAutomationEditKeyMask
 ags_automation_edit_reset_vscrollbar
 ags_automation_edit_reset_hscrollbar
@@ -1367,22 +1372,6 @@ ags_ladspa_browser_plugin_effect_callback
 </SECTION>
 
 <SECTION>
-<FILE>ags_level</FILE>
-<TITLE>AgsLevel</TITLE>
-ags_level_paint
-ags_level_new
-<SUBSECTION Public>
-AGS_IS_LEVEL
-AGS_LEVEL
-AGS_LEVEL_CLASS
-AGS_LEVEL_GET_CLASS
-AGS_TYPE_LEVEL
-AgsLevel
-AgsLevelClass
-ags_level_get_type
-</SECTION>
-
-<SECTION>
 <FILE>ags_level_callbacks</FILE>
 ags_level_expose_event
 ags_level_configure_event
@@ -2018,12 +2007,14 @@ ags_menu_action_add_matrix_callback
 ags_menu_action_add_synth_callback
 ags_menu_action_add_syncsynth_callback
 ags_menu_action_add_ffplayer_callback
+ags_menu_action_add_audiorec_callback
 ags_menu_action_add_ladspa_bridge_callback
 ags_menu_action_add_dssi_bridge_callback
 ags_menu_action_add_lv2_bridge_callback
 ags_menu_action_add_live_dssi_bridge_callback
 ags_menu_action_add_live_lv2_bridge_callback
 ags_menu_action_automation_callback
+ags_menu_action_wave_callback
 ags_menu_action_preferences_callback
 ags_menu_action_midi_import_callback
 ags_menu_action_midi_export_track_callback
@@ -2290,6 +2281,7 @@ AGS_NOTATION_EDIT_MAX_ZOOM
 AGS_NOTATION_EDIT_MAX_ZOOM_CONTROL_WIDTH
 AgsNotationEditFlags
 AgsNotationEditMode
+AgsNotationEditButtonMask
 AgsNotationEditKeyMask
 ags_notation_edit_reset_vscrollbar
 ags_notation_edit_reset_hscrollbar
@@ -3002,6 +2994,21 @@ ags_scrolled_automation_edit_box_get_type
 </SECTION>
 
 <SECTION>
+<FILE>ags_scrolled_wave_edit_box</FILE>
+<TITLE>AgsScrolledWaveEditBox</TITLE>
+ags_scrolled_wave_edit_box_new
+<SUBSECTION Public>
+AGS_IS_SCROLLED_WAVE_EDIT_BOX
+AGS_SCROLLED_WAVE_EDIT_BOX
+AGS_SCROLLED_WAVE_EDIT_BOX_CLASS
+AGS_SCROLLED_WAVE_EDIT_BOX_GET_CLASS
+AGS_TYPE_SCROLLED_WAVE_EDIT_BOX
+AgsScrolledWaveEditBox
+AgsScrolledWaveEditBoxClass
+ags_scrolled_wave_edit_box_get_type
+</SECTION>
+
+<SECTION>
 <FILE>ags_select_acceleration_dialog</FILE>
 <TITLE>AgsSelectAccelerationDialog</TITLE>
 AGS_SELECT_ACCELERATION
@@ -3413,6 +3420,12 @@ ags_track_collection_mapper_get_type
 <TITLE>AgsUiProvider</TITLE>
 ags_ui_provider_get_window
 ags_ui_provider_set_window
+ags_ui_provider_get_gui_thread
+ags_ui_provider_set_gui_thread
+ags_ui_provider_get_show_animation
+ags_ui_provider_set_show_animation
+ags_ui_provider_get_gui_ready
+ags_ui_provider_set_gui_ready
 <SUBSECTION Public>
 AGS_IS_UI_PROVIDER
 AGS_IS_UI_PROVIDER_INTERFACE
@@ -3456,13 +3469,41 @@ ags_vautomation_edit_box_get_type
 </SECTION>
 
 <SECTION>
+<FILE>ags_vwave_edit_box</FILE>
+<TITLE>AgsVWaveEditBox</TITLE>
+ags_vwave_edit_box_new
+<SUBSECTION Public>
+AGS_IS_VWAVE_EDIT_BOX
+AGS_TYPE_VWAVE_EDIT_BOX
+AGS_VWAVE_EDIT_BOX
+AGS_VWAVE_EDIT_BOX_CLASS
+AGS_VWAVE_EDIT_BOX_GET_CLASS
+AgsVWaveEditBox
+AgsVWaveEditBoxClass
+ags_vwave_edit_box_get_type
+</SECTION>
+
+<SECTION>
 <FILE>ags_wave_edit</FILE>
 <TITLE>AgsWaveEdit</TITLE>
-AGS_WAVE_EDIT_MAX_CONTROLS
-AGS_WAVE_EDIT_DEFAULT_MARGIN
+AGS_WAVE_EDIT_DEFAULT_HEIGHT
 AGS_WAVE_EDIT_DEFAULT_WIDTH
+AGS_WAVE_EDIT_DEFAULT_CONTROL_WIDTH
+AGS_WAVE_EDIT_DEFAULT_CONTROL_HEIGHT
+AGS_WAVE_EDIT_DEFAULT_STEP_COUNT
+AGS_WAVE_EDIT_DEFAULT_CURSOR_POSITION_X
+AGS_WAVE_EDIT_DEFAULT_CURSOR_POSITION_Y
+AGS_WAVE_EDIT_DEFAULT_FADER_WIDTH
+AGS_WAVE_EDIT_CURSOR_WIDTH
+AGS_WAVE_EDIT_CURSOR_HEIGHT
+AGS_WAVE_EDIT_MIN_ZOOM
+AGS_WAVE_EDIT_MAX_ZOOM
+AGS_WAVE_EDIT_DEFAULT_LOWER
+AGS_WAVE_EDIT_DEFAULT_UPPER
+AGS_WAVE_EDIT_DEFAULT_VALUE
+AGS_WAVE_EDIT_DEFAULT_PADDING
 AgsWaveEditFlags
-AgsWaveEditResetFlags
+AgsWaveEditMode
 AgsWaveEditKeyMask
 ags_wave_edit_new
 <SUBSECTION Public>
@@ -3477,6 +3518,23 @@ ags_wave_edit_get_type
 </SECTION>
 
 <SECTION>
+<FILE>ags_wave_edit_box</FILE>
+<TITLE>AgsWaveEditBox</TITLE>
+AGS_WAVE_EDIT_BOX_DEFAULT_FIXED_EDIT_HEIGHT
+AgsWaveEditBoxFlags
+ags_wave_edit_box_new
+<SUBSECTION Public>
+AGS_IS_WAVE_EDIT_BOX
+AGS_TYPE_WAVE_EDIT_BOX
+AGS_WAVE_EDIT_BOX
+AGS_WAVE_EDIT_BOX_CLASS
+AGS_WAVE_EDIT_BOX_GET_CLASS
+AgsWaveEditBox
+AgsWaveEditBoxClass
+ags_wave_edit_box_get_type
+</SECTION>
+
+<SECTION>
 <FILE>ags_wave_edit_callbacks</FILE>
 
 </SECTION>
@@ -3484,11 +3542,16 @@ ags_wave_edit_get_type
 <SECTION>
 <FILE>ags_wave_editor</FILE>
 <TITLE>AgsWaveEditor</TITLE>
-AGS_WAVE_EDITOR_CHILD
+AGS_WAVE_EDITOR_MAX_VALUE_COUNT
+AGS_WAVE_EDITOR_MAX_CONTROLS
 AGS_WAVE_EDITOR_DEFAULT_VERSION
 AGS_WAVE_EDITOR_DEFAULT_BUILD_ID
 AgsWaveEditorFlags
+ags_wave_editor_reset_audio_scrollbar
+ags_wave_editor_reset_output_scrollbar
+ags_wave_editor_reset_input_scrollbar
 ags_wave_editor_machine_changed
+ags_wave_editor_select_region
 ags_wave_editor_select_all
 ags_wave_editor_paste
 ags_wave_editor_copy
diff --git a/docs/reference/libgsequencer/libgsequencer.interfaces b/docs/reference/libgsequencer/libgsequencer.interfaces
index 8f3fb7a..e810e5c 100644
--- a/docs/reference/libgsequencer/libgsequencer.interfaces
+++ b/docs/reference/libgsequencer/libgsequencer.interfaces
@@ -78,6 +78,8 @@ GtkHBox AtkImplementorIface GtkBuildable GtkOrientable
 AgsEffectSeparator AtkImplementorIface GtkBuildable GtkOrientable AgsConnectable
 AgsLinkEditor AtkImplementorIface GtkBuildable GtkOrientable AgsConnectable AgsApplicable
 AgsOutputEditor AtkImplementorIface GtkBuildable GtkOrientable AgsConnectable AgsApplicable
+AgsWaveEditBox AtkImplementorIface GtkBuildable GtkOrientable
+AgsVWaveEditBox AtkImplementorIface GtkBuildable GtkOrientable
 GtkBin AtkImplementorIface GtkBuildable
 GtkHandleBox AtkImplementorIface GtkBuildable
 AgsMachine AtkImplementorIface GtkBuildable AgsConnectable AgsPlugin
@@ -128,6 +130,7 @@ GtkCheckButton AtkImplementorIface GtkBuildable GtkActivatable
 GtkRadioButton AtkImplementorIface GtkBuildable GtkActivatable
 AgsMachineRadioButton AtkImplementorIface GtkBuildable GtkActivatable AgsConnectable
 AgsScrolledAutomationEditBox AtkImplementorIface GtkBuildable
+AgsScrolledWaveEditBox AtkImplementorIface GtkBuildable
 GtkTable AtkImplementorIface GtkBuildable
 AgsAutomationEdit AtkImplementorIface GtkBuildable AgsConnectable
 AgsCellPattern AtkImplementorIface GtkBuildable AgsConnectable
@@ -147,8 +150,6 @@ GtkMenu AtkImplementorIface GtkBuildable
 AgsContextMenu AtkImplementorIface GtkBuildable AgsConnectable
 GtkMenuBar AtkImplementorIface GtkBuildable
 AgsMenuBar AtkImplementorIface GtkBuildable AgsConnectable
-GtkDrawingArea AtkImplementorIface GtkBuildable
-AgsLevel AtkImplementorIface GtkBuildable AgsConnectable
 AgsThread AgsConnectable
 AgsGuiThread AgsConnectable
 AgsSimpleAutosaveThread AgsConnectable
diff --git a/docs/reference/libgsequencer/libgsequencer.types b/docs/reference/libgsequencer/libgsequencer.types
index f0fdbe0..c5f8009 100644
--- a/docs/reference/libgsequencer/libgsequencer.types
+++ b/docs/reference/libgsequencer/libgsequencer.types
@@ -47,7 +47,6 @@ ags_history_browser_get_type
 ags_inline_player_get_type
 ags_ladspa_bridge_get_type
 ags_ladspa_browser_get_type
-ags_level_get_type
 ags_line_editor_get_type
 ags_line_get_type
 ags_line_member_editor_get_type
@@ -107,6 +106,7 @@ ags_ramp_acceleration_dialog_get_type
 ags_remove_sequencer_editor_jack_get_type
 ags_remove_soundcard_editor_sink_get_type
 ags_scrolled_automation_edit_box_get_type
+ags_scrolled_wave_edit_box_get_type
 ags_select_acceleration_dialog_get_type
 ags_select_note_dialog_get_type
 ags_sequencer_editor_get_type
@@ -127,6 +127,8 @@ ags_track_collection_mapper_get_type
 ags_ui_provider_get_type
 ags_update_bulk_member_get_type
 ags_vautomation_edit_box_get_type
+ags_vwave_edit_box_get_type
+ags_wave_edit_box_get_type
 ags_wave_edit_get_type
 ags_wave_editor_get_type
 ags_wave_toolbar_get_type
diff --git a/gsequencer.share/styles/ags.rc b/gsequencer.share/styles/ags.rc
index 00937d6..45a3851 100644
--- a/gsequencer.share/styles/ags.rc
+++ b/gsequencer.share/styles/ags.rc
@@ -76,6 +76,7 @@ style "main_window" = "default_widget"
 
 widget_class "AgsWindow*" style "main_window"
 widget_class "AgsAutomationWindow*" style "main_window"
+widget_class "AgsWaveWindow*" style "main_window"
 widget_class "GtkWindow*" style "main_window"
 widget_class "AgsPreferences*" style "main_window"
 widget_class "AgsMidiImportWizard*" style "main_window"
@@ -104,6 +105,7 @@ widget_class "*GtkHandleBox*" style "default_widget"
 
 widget_class "*AgsNotationToolbar*" style "inverse_widget"
 widget_class "*AgsAutomationToolbar*" style "inverse_widget"
+widget_class "*AgsWaveToolbar*" style "inverse_widget"
 widget_class "*AgsMenuBar*" style "inverse_widget"
 widget_class "*AgsContextMenu*" style "inverse_widget"
 widget_class "*AgsNotebook*" style "default_widget"
diff --git a/libags.sym b/libags.sym
index 2d52499..b6e66fa 100644
--- a/libags.sym
+++ b/libags.sym
@@ -20,6 +20,16 @@ ags_function_symbolic_translate_value
 ags_function_substitute_values
 ags_function_translate_value
 ags_function_new
+ags_buffer_util_s8_to_char_buffer
+ags_buffer_util_s16_to_char_buffer
+ags_buffer_util_s24_to_char_buffer
+ags_buffer_util_s32_to_char_buffer
+ags_buffer_util_s64_to_char_buffer
+ags_buffer_util_char_buffer_to_s8
+ags_buffer_util_char_buffer_to_s16
+ags_buffer_util_char_buffer_to_s24
+ags_buffer_util_char_buffer_to_s32
+ags_buffer_util_char_buffer_to_s64
 ags_string_util_escape_single_quote
 ags_strv_length
 ags_strv_contains
diff --git a/libags_audio.sym b/libags_audio.sym
index fb4edb2..99fdf88 100644
--- a/libags_audio.sym
+++ b/libags_audio.sym
@@ -207,6 +207,7 @@ ags_recall_child_added
 ags_recall_run_init_pre
 ags_recall_run_init_inter
 ags_recall_run_init_post
+ags_recall_check_rt_stream
 ags_recall_automate
 ags_recall_run_pre
 ags_recall_run_inter
@@ -636,6 +637,8 @@ ags_audio_signal_stream_resize
 ags_audio_signal_stream_safe_resize
 ags_audio_signal_realloc_buffer_size
 ags_audio_signal_duplicate_stream
+ags_audio_signal_add_note
+ags_audio_signal_remove_note
 ags_audio_signal_get_template
 ags_audio_signal_get_stream_current
 ags_audio_signal_get_by_recall_id
@@ -854,6 +857,8 @@ ags_audio_add_notation
 ags_audio_remove_notation
 ags_audio_add_automation
 ags_audio_remove_automation
+ags_audio_add_wave
+ags_audio_remove_wave
 ags_audio_add_recall_id
 ags_audio_remove_recall_id
 ags_audio_add_recycling_context
@@ -1186,6 +1191,8 @@ ags_loop_channel_run_get_type
 ags_loop_channel_run_new
 ags_copy_recycling_get_type
 ags_copy_recycling_new
+ags_rt_stream_recycling_get_type
+ags_rt_stream_recycling_new
 ags_play_notation_audio_get_type
 ags_play_notation_audio_new
 ags_buffer_channel_run_get_type
@@ -1194,6 +1201,8 @@ ags_route_dssi_audio_get_type
 ags_route_dssi_audio_new
 ags_play_channel_run_get_type
 ags_play_channel_run_new
+ags_capture_sound_audio_get_type
+ags_capture_sound_audio_new
 ags_peak_channel_run_get_type
 ags_peak_channel_run_new
 ags_play_recycling_get_type
@@ -1219,6 +1228,8 @@ ags_mute_channel_run_get_type
 ags_mute_channel_run_new
 ags_prepare_audio_signal_get_type
 ags_prepare_audio_signal_new
+ags_rt_stream_channel_run_get_type
+ags_rt_stream_channel_run_new
 ags_stream_channel_run_get_type
 ags_stream_channel_run_new
 ags_play_audio_file_get_type
@@ -1249,6 +1260,8 @@ ags_feed_channel_get_type
 ags_feed_channel_new
 ags_envelope_channel_get_type
 ags_envelope_channel_new
+ags_capture_sound_audio_run_get_type
+ags_capture_sound_audio_run_new
 ags_play_channel_run_master_get_type
 ags_play_channel_run_master_streamer_free
 ags_play_channel_run_master_streamer_alloc
@@ -1262,12 +1275,16 @@ ags_play_notation_audio_run_get_type
 ags_play_notation_audio_run_new
 ags_peak_recycling_get_type
 ags_peak_recycling_new
+ags_rt_stream_channel_get_type
+ags_rt_stream_channel_new
 ags_feed_channel_run_get_type
 ags_feed_channel_run_new
 ags_volume_channel_get_type
 ags_volume_channel_new
 ags_volume_audio_signal_get_type
 ags_volume_audio_signal_new
+ags_rt_stream_audio_signal_get_type
+ags_rt_stream_audio_signal_new
 ags_recall_ladspa_get_type
 ags_recall_ladspa_load
 ags_recall_ladspa_load_ports
@@ -1432,6 +1449,33 @@ ags_recall_recycling_dummy_get_type
 ags_recall_recycling_dummy_new
 ags_recall_lv2_run_get_type
 ags_recall_lv2_run_new
+ags_wave_get_type
+ags_wave_set_samplerate
+ags_wave_set_buffer_size
+ags_wave_set_format
+ags_wave_find_near_timestamp
+ags_wave_add
+ags_wave_add_buffer
+ags_wave_remove_buffer
+ags_wave_get_selection
+ags_wave_is_buffer_selected
+ags_wave_find_region
+ags_wave_free_selection
+ags_wave_add_region_to_selection
+ags_wave_remove_region_from_selection
+ags_wave_add_all_to_selection
+ags_wave_copy_selection
+ags_wave_cut_selection
+ags_wave_insert_from_clipboard
+ags_wave_insert_from_clipboard_extended
+ags_wave_new
+ags_buffer_get_type
+ags_buffer_set_samplerate
+ags_buffer_set_buffer_size
+ags_buffer_set_format
+ags_buffer_sort_func
+ags_buffer_duplicate
+ags_buffer_new
 ags_recycling_context_get_type
 ags_recycling_context_replace
 ags_recycling_context_add
diff --git a/libags_gui.sym b/libags_gui.sym
index 0504fd5..917d83c 100644
--- a/libags_gui.sym
+++ b/libags_gui.sym
@@ -11,13 +11,18 @@ ags_led_get_type
 ags_led_set_active
 ags_led_unset_active
 ags_led_new
+ags_level_get_type
+ags_level_new
 ags_scale_get_type
+ags_scale_value_changed
 ags_scale_new
 ags_table_get_type
 ags_table_new
 ags_container_add_all
 ags_hindicator_get_type
 ags_hindicator_new
+ags_level_box_get_type
+ags_level_box_new
 ags_hled_array_get_type
 ags_hled_array_new
 ags_scale_box_get_type
@@ -68,6 +73,8 @@ ags_expander_remove
 ags_expander_new
 ags_scrolled_piano_get_type
 ags_scrolled_piano_new
+ags_vlevel_box_get_type
+ags_vlevel_box_new
 ags_htimebar_new
 ags_indicator_get_type
 ags_indicator_new
@@ -81,6 +88,8 @@ ags_expander_set_remove
 ags_expander_set_new
 ags_vscale_box_get_type
 ags_vscale_box_new
+ags_scrolled_level_box_get_type
+ags_scrolled_level_box_new
 ags_ruler_get_type
 ags_ruler_new
 ags_waveform_get_type
@@ -90,5 +99,7 @@ ags_led_array_set_led_count
 ags_led_array_unset_all
 ags_led_array_set_nth
 ags_led_array_new
+ags_hlevel_box_get_type
+ags_hlevel_box_new
 ags_scrolled_scale_box_get_type
 ags_scrolled_scale_box_new
diff --git a/po/POTFILES.in b/po/POTFILES.in
index f38ceef..b46caf4 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -117,8 +117,6 @@
 ./ags/X/editor/ags_file_selection_callbacks.c
 ./ags/X/editor/ags_inline_player.c
 ./ags/X/editor/ags_inline_player_callbacks.c
-./ags/X/editor/ags_level.c
-./ags/X/editor/ags_level_callbacks.c
 ./ags/X/editor/ags_machine_radio_button.c
 ./ags/X/editor/ags_machine_radio_button_callbacks.c
 ./ags/X/editor/ags_machine_selection.c
@@ -139,6 +137,7 @@
 ./ags/X/editor/ags_ramp_acceleration_dialog.c
 ./ags/X/editor/ags_ramp_acceleration_dialog_callbacks.c
 ./ags/X/editor/ags_scrolled_automation_edit_box.c
+./ags/X/editor/ags_scrolled_wave_edit_box.c
 ./ags/X/editor/ags_select_acceleration_dialog.c
 ./ags/X/editor/ags_select_acceleration_dialog_callbacks.c
 ./ags/X/editor/ags_select_note_dialog.c
@@ -146,7 +145,9 @@
 ./ags/X/editor/ags_sf2_chooser.c
 ./ags/X/editor/ags_sf2_chooser_callbacks.c
 ./ags/X/editor/ags_vautomation_edit_box.c
+./ags/X/editor/ags_vwave_edit_box.c
 ./ags/X/editor/ags_wave_edit.c
+./ags/X/editor/ags_wave_edit_box.c
 ./ags/X/editor/ags_wave_edit_callbacks.c
 ./ags/X/editor/ags_wave_toolbar.c
 ./ags/X/editor/ags_wave_toolbar_callbacks.c
@@ -247,6 +248,7 @@
 ./ags/audio/ags_audio_connection.c
 ./ags/audio/ags_audio_signal.c
 ./ags/audio/ags_automation.c
+./ags/audio/ags_buffer.c
 ./ags/audio/ags_channel.c
 ./ags/audio/ags_channel_iter.c
 ./ags/audio/ags_devin.c
@@ -289,6 +291,7 @@
 ./ags/audio/ags_sound_provider.c
 ./ags/audio/ags_synth_generator.c
 ./ags/audio/ags_synth_util.c
+./ags/audio/ags_wave.c
 ./ags/audio/client/ags_remote_channel.c
 ./ags/audio/client/ags_remote_input.c
 ./ags/audio/client/ags_remote_output.c
@@ -325,6 +328,8 @@
 ./ags/audio/recall/ags_buffer_channel.c
 ./ags/audio/recall/ags_buffer_channel_run.c
 ./ags/audio/recall/ags_buffer_recycling.c
+./ags/audio/recall/ags_capture_sound_audio.c
+./ags/audio/recall/ags_capture_sound_audio_run.c
 ./ags/audio/recall/ags_copy_audio_signal.c
 ./ags/audio/recall/ags_copy_channel.c
 ./ags/audio/recall/ags_copy_channel_run.c
@@ -383,6 +388,10 @@
 ./ags/audio/recall/ags_route_dssi_audio_run.c
 ./ags/audio/recall/ags_route_lv2_audio.c
 ./ags/audio/recall/ags_route_lv2_audio_run.c
+./ags/audio/recall/ags_rt_stream_audio_signal.c
+./ags/audio/recall/ags_rt_stream_channel.c
+./ags/audio/recall/ags_rt_stream_channel_run.c
+./ags/audio/recall/ags_rt_stream_recycling.c
 ./ags/audio/recall/ags_stream_audio_signal.c
 ./ags/audio/recall/ags_stream_channel.c
 ./ags/audio/recall/ags_stream_channel_run.c
@@ -469,6 +478,7 @@
 ./ags/file/ags_file_lookup.c
 ./ags/file/ags_file_util.c
 ./ags/file/ags_xml_serialization_factory.c
+./ags/lib/ags_buffer_util.c
 ./ags/lib/ags_complex.c
 ./ags/lib/ags_conversion.c
 ./ags/lib/ags_endian.c
@@ -581,22 +591,27 @@
 ./ags/widget/ags_expander_set.c
 ./ags/widget/ags_hindicator.c
 ./ags/widget/ags_hled_array.c
+./ags/widget/ags_hlevel_box.c
 ./ags/widget/ags_hscale_box.c
 ./ags/widget/ags_htimebar.c
 ./ags/widget/ags_indicator.c
 ./ags/widget/ags_led.c
 ./ags/widget/ags_led_array.c
+./ags/widget/ags_level.c
+./ags/widget/ags_level_box.c
 ./ags/widget/ags_notebook.c
 ./ags/widget/ags_piano.c
 ./ags/widget/ags_ruler.c
 ./ags/widget/ags_scale.c
 ./ags/widget/ags_scale_box.c
+./ags/widget/ags_scrolled_level_box.c
 ./ags/widget/ags_scrolled_piano.c
 ./ags/widget/ags_scrolled_scale_box.c
 ./ags/widget/ags_table.c
 ./ags/widget/ags_timebar.c
 ./ags/widget/ags_vindicator.c
 ./ags/widget/ags_vled_array.c
+./ags/widget/ags_vlevel_box.c
 ./ags/widget/ags_vscale_box.c
 ./ags/widget/ags_waveform.c
 ./ags/widget/ags_widget_marshal.c
diff --git a/po/gsequencer.pot b/po/gsequencer.pot
index e18bc5d..d3c615b 100644
--- a/po/gsequencer.pot
+++ b/po/gsequencer.pot
@@ -6,9 +6,9 @@
 #, fuzzy
 msgid ""
 msgstr ""
-"Project-Id-Version: gsequencer 1.3.3\n"
+"Project-Id-Version: gsequencer 1.4.5\n"
 "Report-Msgid-Bugs-To: jkraehemann-guest at users.alioth.debian.org\n"
-"POT-Creation-Date: 2018-01-06 06:49+0100\n"
+"POT-Creation-Date: 2018-01-16 14:12+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
 "Language-Team: LANGUAGE <LL at li.org>\n"
@@ -37,24 +37,25 @@ msgstr ""
 msgid "connect sink"
 msgstr ""
 
-#: ags/X/ags_automation_editor.c:231
+#: ags/X/ags_automation_editor.c:239
 msgid "automation"
 msgstr ""
 
-#: ags/X/ags_automation_editor.c:255 ags/X/ags_preferences.c:179
+#: ags/X/ags_automation_editor.c:271 ags/X/ags_preferences.c:179
 msgid "audio"
 msgstr ""
 
-#: ags/X/ags_automation_editor.c:326 ags/X/ags_connection_editor.c:217
+#: ags/X/ags_automation_editor.c:342 ags/X/ags_connection_editor.c:217
 #: ags/X/ags_machine_editor.c:217
 msgid "output"
 msgstr ""
 
-#: ags/X/ags_automation_editor.c:351 ags/X/ags_automation_editor.c:435
+#: ags/X/ags_automation_editor.c:367 ags/X/ags_automation_editor.c:451
+#: ags/X/ags_wave_editor.c:286
 msgid "line"
 msgstr ""
 
-#: ags/X/ags_automation_editor.c:410 ags/X/ags_machine_editor.c:224
+#: ags/X/ags_automation_editor.c:426 ags/X/ags_machine_editor.c:224
 msgid "input"
 msgstr ""
 
@@ -72,53 +73,53 @@ msgid "connect output"
 msgstr ""
 
 #: ags/X/ags_context_menu.c:151 ags/X/ags_export_window.c:342
-#: ags/X/ags_menu_bar.c:147
+#: ags/X/ags_menu_bar.c:143
 msgid "export"
 msgstr ""
 
-#: ags/X/ags_context_menu.c:179 ags/X/ags_menu_bar.c:175
+#: ags/X/ags_context_menu.c:179 ags/X/ags_menu_bar.c:171
 msgid "Panel"
 msgstr ""
 
-#: ags/X/ags_context_menu.c:182 ags/X/ags_menu_bar.c:178
+#: ags/X/ags_context_menu.c:182 ags/X/ags_menu_bar.c:174
 msgid "Mixer"
 msgstr ""
 
-#: ags/X/ags_context_menu.c:185 ags/X/ags_menu_bar.c:181
+#: ags/X/ags_context_menu.c:185 ags/X/ags_menu_bar.c:177
 msgid "Drum"
 msgstr ""
 
-#: ags/X/ags_context_menu.c:188 ags/X/ags_menu_bar.c:184
+#: ags/X/ags_context_menu.c:188 ags/X/ags_menu_bar.c:180
 msgid "Matrix"
 msgstr ""
 
-#: ags/X/ags_context_menu.c:191 ags/X/ags_menu_bar.c:187
+#: ags/X/ags_context_menu.c:191 ags/X/ags_menu_bar.c:183
 msgid "Synth"
 msgstr ""
 
-#: ags/X/ags_context_menu.c:194 ags/X/ags_menu_bar.c:190
+#: ags/X/ags_context_menu.c:194 ags/X/ags_menu_bar.c:186
 msgid "Syncsynth"
 msgstr ""
 
-#: ags/X/ags_context_menu.c:198 ags/X/ags_menu_bar.c:194
+#: ags/X/ags_context_menu.c:198 ags/X/ags_menu_bar.c:190
 msgid "FPlayer"
 msgstr ""
 
-#: ags/X/ags_context_menu.c:203 ags/X/ags_menu_bar.c:199
+#: ags/X/ags_context_menu.c:203 ags/X/ags_menu_bar.c:200
 msgid "LADSPA"
 msgstr ""
 
 #: ags/X/ags_context_menu.c:207 ags/X/ags_context_menu.c:222
-#: ags/X/ags_menu_bar.c:203 ags/X/ags_menu_bar.c:218
+#: ags/X/ags_menu_bar.c:204 ags/X/ags_menu_bar.c:219
 msgid "DSSI"
 msgstr ""
 
 #: ags/X/ags_context_menu.c:211 ags/X/ags_context_menu.c:226
-#: ags/X/ags_menu_bar.c:207 ags/X/ags_menu_bar.c:222
+#: ags/X/ags_menu_bar.c:208 ags/X/ags_menu_bar.c:223
 msgid "Lv2"
 msgstr ""
 
-#: ags/X/ags_context_menu.c:231 ags/X/ags_menu_bar.c:227
+#: ags/X/ags_context_menu.c:231 ags/X/ags_menu_bar.c:228
 msgid "Automation"
 msgstr ""
 
@@ -211,7 +212,7 @@ msgstr ""
 msgid "live export"
 msgstr ""
 
-#: ags/X/ags_export_window.c:220 ags/X/ags_navigation.c:306
+#: ags/X/ags_export_window.c:220 ags/X/ags_navigation.c:298
 msgid "exclude sequencers"
 msgstr ""
 
@@ -239,7 +240,7 @@ msgstr ""
 msgid "engine mode"
 msgstr ""
 
-#: ags/X/ags_line.c:721 ags/X/ags_line.c:729 ags/X/ags_notation_editor.c:260
+#: ags/X/ags_line.c:721 ags/X/ags_line.c:729 ags/X/ags_notation_editor.c:277
 msgid "channel"
 msgstr ""
 
@@ -284,6 +285,10 @@ msgstr ""
 msgid "M-Box"
 msgstr ""
 
+#: ags/X/ags_machine.c:2021 ags/X/machine/ags_audiorec_callbacks.c:37
+msgid "Open audio files"
+msgstr ""
+
 #: ags/X/ags_machine.c:2029
 msgid "open in new channel"
 msgstr ""
@@ -365,6 +370,14 @@ msgstr ""
 msgid "resize channels"
 msgstr ""
 
+#: ags/X/ags_menu_bar.c:195
+msgid "Audiorec"
+msgstr ""
+
+#: ags/X/ags_menu_bar.c:235
+msgid "Wave"
+msgstr ""
+
 #: ags/X/ags_midi_dialog.c:208
 msgid "midi channel"
 msgstr ""
@@ -389,23 +402,23 @@ msgstr ""
 msgid "midi device"
 msgstr ""
 
-#: ags/X/ags_navigation.c:211
+#: ags/X/ags_navigation.c:203
 msgid "bpm"
 msgstr ""
 
-#: ags/X/ags_navigation.c:251 ags/X/machine/ags_drum.c:287
+#: ags/X/ags_navigation.c:243 ags/X/machine/ags_drum.c:287
 msgid "loop"
 msgstr ""
 
-#: ags/X/ags_navigation.c:284
+#: ags/X/ags_navigation.c:276
 msgid "loop L"
 msgstr ""
 
-#: ags/X/ags_navigation.c:290
+#: ags/X/ags_navigation.c:282
 msgid "loop R"
 msgstr ""
 
-#: ags/X/ags_notation_editor.c:236
+#: ags/X/ags_notation_editor.c:245
 msgid "notation"
 msgstr ""
 
@@ -508,25 +521,25 @@ msgstr ""
 msgid "format"
 msgstr ""
 
-#: ags/X/ags_wave_editor.c:215 ags/X/machine/ags_oscillator.c:155
+#: ags/X/ags_wave_editor.c:237 ags/X/machine/ags_oscillator.c:155
 msgid "wave"
 msgstr ""
 
-#: ags/X/ags_xorg_application_context.c:1303
+#: ags/X/ags_xorg_application_context.c:1363
 #, c-format
 msgid "unknown soundcard backend - %s"
 msgstr ""
 
-#: ags/X/ags_xorg_application_context.c:1313
+#: ags/X/ags_xorg_application_context.c:1373
 msgid "unknown soundcard backend - NULL"
 msgstr ""
 
-#: ags/X/ags_xorg_application_context.c:1462
+#: ags/X/ags_xorg_application_context.c:1522
 #, c-format
 msgid "unknown sequencer backend - %s"
 msgstr ""
 
-#: ags/X/ags_xorg_application_context.c:1472
+#: ags/X/ags_xorg_application_context.c:1532
 msgid "unknown sequencer backend - NULL"
 msgstr ""
 
@@ -623,7 +636,7 @@ msgstr ""
 
 #: ags/X/editor/ags_envelope_editor.c:176
 #: ags/X/editor/ags_pattern_envelope.c:240 ags/X/machine/ags_ffplayer.c:269
-#: ags/X/machine/ags_live_lv2_bridge.c:1623 ags/X/machine/ags_lv2_bridge.c:1948
+#: ags/X/machine/ags_live_lv2_bridge.c:1623 ags/X/machine/ags_lv2_bridge.c:2003
 msgid "preset"
 msgstr ""
 
@@ -898,7 +911,7 @@ msgid "channel: "
 msgstr ""
 
 #: ags/X/machine/ags_dssi_bridge.c:318 ags/X/machine/ags_live_dssi_bridge.c:318
-#: ags/X/machine/ags_live_lv2_bridge.c:1562 ags/X/machine/ags_lv2_bridge.c:1887
+#: ags/X/machine/ags_live_lv2_bridge.c:1562 ags/X/machine/ags_lv2_bridge.c:1942
 msgid "program"
 msgstr ""
 

-- 
gsequencer packaging



More information about the pkg-multimedia-commits mailing list