diff --git a/gtk2_ardour/audio_time_axis.cc b/gtk2_ardour/audio_time_axis.cc
index b009508..fd809a9 100644
--- a/gtk2_ardour/audio_time_axis.cc
+++ b/gtk2_ardour/audio_time_axis.cc
@@ -446,7 +446,7 @@ AudioTimeAxisView::build_automation_action_menu ()
 	gain_automation_item = dynamic_cast<CheckMenuItem*> (&automation_items.back ());
 	gain_automation_item->set_active (gain_track->marked_for_display ());
 
-	_parameter_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
+	_main_automation_menu_map[Evoral::Parameter(GainAutomation)] = gain_automation_item;
 
 	automation_items.push_back (CheckMenuElem (_("Pan"), sigc::mem_fun (*this, &AudioTimeAxisView::update_pan_track_visibility)));
 	pan_automation_item = dynamic_cast<CheckMenuItem*> (&automation_items.back ());
@@ -454,7 +454,7 @@ AudioTimeAxisView::build_automation_action_menu ()
 
 	set<Evoral::Parameter> const & params = _route->panner()->what_can_be_automated ();
 	for (set<Evoral::Parameter>::iterator p = params.begin(); p != params.end(); ++p) {
-		_parameter_menu_map[*p] = pan_automation_item;
+		_main_automation_menu_map[*p] = pan_automation_item;
 	}
 }
 
diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc
index 62edad9..7977edd 100644
--- a/gtk2_ardour/editor.cc
+++ b/gtk2_ardour/editor.cc
@@ -574,10 +574,11 @@ Editor::Editor ()
 	the_notebook.show_all ();
 	
 	post_maximal_editor_width = 0;
-	post_maximal_pane_position = 0;
+	post_maximal_horizontal_pane_position = 0;
+	post_maximal_editor_height = 0;
+	post_maximal_vertical_pane_position = 0;
 
-	VPaned *editor_summary_pane = manage(new VPaned());
-	editor_summary_pane->pack1(edit_packer);
+	editor_summary_pane.pack1(edit_packer);
 
 	Button* summary_arrows_left_left = manage (new Button);
 	summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
@@ -608,11 +609,15 @@ Editor::Editor ()
 	_summary_hbox.pack_start (*summary_frame, true, true);
 	_summary_hbox.pack_start (*summary_arrows_right, false, false);
 	
-	editor_summary_pane->pack2 (_summary_hbox);
+	editor_summary_pane.pack2 (_summary_hbox);
 
-	edit_pane.pack1 (*editor_summary_pane, true, true);
+	edit_pane.pack1 (editor_summary_pane, true, true);
 	edit_pane.pack2 (the_notebook, false, true);
 
+	editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
+
+	/* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
+
 	edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
 #ifdef GTKOSX
         Glib::PropertyProxy<int> proxy = edit_pane.property_position();
@@ -2406,10 +2411,6 @@ Editor::set_state (const XMLNode& node, int /*version*/)
 		the_notebook.set_current_page (atoi (prop->value ()));
 	}
 
-	if ((prop = node.property (X_("editor-pane-position")))) {
-		edit_pane.set_position (atoi (prop->value ()));
-	}
-
 	return 0;
 }
 
@@ -2445,7 +2446,9 @@ Editor::get_state ()
 		snprintf(buf, sizeof(buf), "%d", yoff);
 		geometry->add_property("y-off", string(buf));
 		snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
-		geometry->add_property("edit_pane_pos", string(buf));
+		geometry->add_property("edit-horizontal-pane-pos", string(buf));
+		snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
+		geometry->add_property("edit-vertical-pane-pos", string(buf));
 
 		node->add_child_nocopy (*geometry);
 	}
@@ -2494,9 +2497,6 @@ Editor::get_state ()
 	snprintf (buf, sizeof (buf), "%d", the_notebook.get_current_page ());
 	node->add_property (X_("editor-list-page"), buf);
 
-	snprintf (buf, sizeof (buf), "%d", edit_pane.get_position ());
-	node->add_property (X_("editor-pane-position"), buf);
-
 	return *node;
 }
 
@@ -3669,7 +3669,14 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
 	char buf[32];
 	XMLNode* node = ARDOUR_UI::instance()->editor_settings();
 	int width, height;
-	static int32_t done;
+
+	enum Pane {
+		Horizontal = 0x1,
+		Vertical = 0x2
+	};
+
+	static Pane done;
+	
 	XMLNode* geometry;
 
 	width = default_width;
@@ -3677,15 +3684,11 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
 
 	if ((geometry = find_named_node (*node, "geometry")) != 0) {
 
-		if ((prop = geometry->property ("x_size")) == 0) {
-			prop = geometry->property ("x-size");
-		}
+		prop = geometry->property ("x-size");
 		if (prop) {
 			width = atoi (prop->value());
 		}
-		if ((prop = geometry->property ("y_size")) == 0) {
-			prop = geometry->property ("y-size");
-		}
+		prop = geometry->property ("y-size");
 		if (prop) {
 			height = atoi (prop->value());
 		}
@@ -3693,11 +3696,11 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
 
 	if (which == static_cast<Paned*> (&edit_pane)) {
 
-		if (done) {
+		if (done & Horizontal) {
 			return;
 		}
 
-		if (!geometry || (prop = geometry->property ("edit-pane-pos")) == 0) {
+		if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
 			/* initial allocation is 90% to canvas, 10% to notebook */
 			pos = (int) floor (alloc.get_width() * 0.90f);
 			snprintf (buf, sizeof(buf), "%d", pos);
@@ -3705,10 +3708,33 @@ Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
 			pos = atoi (prop->value());
 		}
 
-		if ((done = GTK_WIDGET(edit_pane.gobj())->allocation.width > pos)) {
+		if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
 			edit_pane.set_position (pos);
-			pre_maximal_pane_position = pos;
+			pre_maximal_horizontal_pane_position = pos;
+		}
+
+		done = (Pane) (done | Horizontal);
+		
+	} else if (which == static_cast<Paned*> (&editor_summary_pane)) {
+
+		if (done & Vertical) {
+			return;
+		}
+
+		if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
+			/* initial allocation is 90% to canvas, 10% to summary */
+			pos = (int) floor (alloc.get_height() * 0.90f);
+			snprintf (buf, sizeof(buf), "%d", pos);
+		} else {
+			pos = atoi (prop->value());
+		}
+
+		if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
+			editor_summary_pane.set_position (pos);
+			pre_maximal_vertical_pane_position = pos;
 		}
+
+		done = (Pane) (done | Vertical);
 	}
 }
 
@@ -4053,39 +4079,58 @@ Editor::maximise_editing_space ()
 	_mouse_mode_tearoff->set_visible (false);
 	_tools_tearoff->set_visible (false);
 
-	pre_maximal_pane_position = edit_pane.get_position();
-	pre_maximal_editor_width = this->get_width();
+	pre_maximal_horizontal_pane_position = edit_pane.get_position ();
+	pre_maximal_vertical_pane_position = editor_summary_pane.get_position ();
+	pre_maximal_editor_width = this->get_width ();
+	pre_maximal_editor_height = this->get_height ();
 
-	if(post_maximal_pane_position == 0) {
-		post_maximal_pane_position = edit_pane.get_width();
+	if (post_maximal_horizontal_pane_position == 0) {
+		post_maximal_horizontal_pane_position = edit_pane.get_width();
 	}
 
-	fullscreen();
+	if (post_maximal_vertical_pane_position == 0) {
+		post_maximal_vertical_pane_position = editor_summary_pane.get_height();
+	}
+	
+	fullscreen ();
 
-	if(post_maximal_editor_width) {
-		edit_pane.set_position (post_maximal_pane_position -
+	if (post_maximal_editor_width) {
+		edit_pane.set_position (post_maximal_horizontal_pane_position -
 			abs(post_maximal_editor_width - pre_maximal_editor_width));
 	} else {
-		edit_pane.set_position (post_maximal_pane_position);
+		edit_pane.set_position (post_maximal_horizontal_pane_position);
+	}
+
+	if (post_maximal_editor_height) {
+		editor_summary_pane.set_position (post_maximal_vertical_pane_position -
+			abs(post_maximal_editor_height - pre_maximal_editor_height));
+	} else {
+		editor_summary_pane.set_position (post_maximal_vertical_pane_position);
 	}
 }
 
 void
 Editor::restore_editing_space ()
 {
-	// user changed width of pane during fullscreen
+	// user changed width/height of panes during fullscreen
 
-	if(post_maximal_pane_position != edit_pane.get_position()) {
-		post_maximal_pane_position = edit_pane.get_position();
+	if (post_maximal_horizontal_pane_position != edit_pane.get_position()) {
+		post_maximal_horizontal_pane_position = edit_pane.get_position();
 	}
 
+	if (post_maximal_vertical_pane_position != editor_summary_pane.get_position()) {
+		post_maximal_vertical_pane_position = editor_summary_pane.get_position();
+	}
+	
 	unfullscreen();
 
 	_mouse_mode_tearoff->set_visible (true);
 	_tools_tearoff->set_visible (true);
 	post_maximal_editor_width = this->get_width();
+	post_maximal_editor_height = this->get_height();
 
-	edit_pane.set_position (pre_maximal_pane_position + abs(this->get_width() - pre_maximal_editor_width));
+	edit_pane.set_position (pre_maximal_horizontal_pane_position + abs(this->get_width() - pre_maximal_editor_width));
+	editor_summary_pane.set_position (pre_maximal_vertical_pane_position + abs(this->get_height() - pre_maximal_editor_height));
 }
 
 /**
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index ae5bb6f..95fbde8 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -513,13 +513,18 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
 	void update_join_object_range_location (double, double);
 
 	int  post_maximal_editor_width;
-	int  post_maximal_pane_position;
-	int  pre_maximal_pane_position;
+	int  post_maximal_editor_height;
+	int  post_maximal_horizontal_pane_position;
+	int  post_maximal_vertical_pane_position;
+	int  pre_maximal_horizontal_pane_position;
+	int  pre_maximal_vertical_pane_position;
 	int  pre_maximal_editor_width;
+	int  pre_maximal_editor_height;
 	void pane_allocation_handler (Gtk::Allocation&, Gtk::Paned*);
 
 	Gtk::Notebook the_notebook;
 	Gtk::HPaned   edit_pane;
+	Gtk::VPaned   editor_summary_pane;
 
 	Gtk::EventBox meter_base;
 	Gtk::HBox     meter_box;
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc
index 7c8c192..3021104 100644
--- a/gtk2_ardour/editor_drag.cc
+++ b/gtk2_ardour/editor_drag.cc
@@ -1592,15 +1592,15 @@ NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
 void
 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
 {
-	Gdk::Cursor     cursor;
-	ArdourCanvas::CanvasNote*     cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
+	Gdk::Cursor cursor;
+	ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
 
 	Drag::start_grab (event);
 
 	region = &cnote->region_view();
 
-	double region_start = region->get_position_pixels();
-	double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
+	double const region_start = region->get_position_pixels();
+	double const middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
 
 	if (grab_x() <= middle_point) {
 		cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
@@ -1644,7 +1644,7 @@ NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
 {
 	MidiRegionSelection& ms (_editor->get_selection().midi_regions);
 	for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
-		(*r)->update_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
+		(*r)->update_resizing (dynamic_cast<ArdourCanvas::CanvasNote*>(_item), at_front, _drags->current_pointer_x() - grab_x(), relative);
 	}
 }
 
@@ -1653,7 +1653,7 @@ NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
 {
 	MidiRegionSelection& ms (_editor->get_selection().midi_regions);
 	for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
-		(*r)->commit_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
+		(*r)->commit_resizing (dynamic_cast<ArdourCanvas::CanvasNote*>(_item), at_front, _drags->current_pointer_x() - grab_x(), relative);
 	}
 }
 
@@ -3768,7 +3768,6 @@ NoteDrag::motion (GdkEvent*, bool)
                                                                cnote->note()->length(), 
                                                                cnote->note()->note() + drag_delta_note,
                                                                cnote->note()->velocity()));
-                bool overlaps = cnote->region_view().midi_region()->model()->overlaps (check_note, cnote->note());
 
 		region->move_selection (dx, dy);
 
diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc
index 9b14bcd..9206f15 100644
--- a/gtk2_ardour/editor_ops.cc
+++ b/gtk2_ardour/editor_ops.cc
@@ -3662,6 +3662,8 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
 		InterThreadInfo itt;
 
                 playlist->clear_history ();
+		playlist->clear_owned_history ();
+		
 		boost::shared_ptr<Region> r = rtv->track()->bounce_range (start, start+cnt, itt, enable_processing);
 
 		if (replace) {
@@ -3671,7 +3673,13 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
 			playlist->add_region (r, start);
 		}
 
-		_session->add_command (new StatefulDiffCommand (playlist));
+		vector<StatefulDiffCommand*> cmds;
+		playlist->rdiff (cmds);
+		for (vector<StatefulDiffCommand*>::iterator j = cmds.begin(); j != cmds.end(); ++j) {
+			_session->add_command (*j);
+		}
+
+                _session->add_command (new StatefulDiffCommand (playlist));
 	}
 
 	commit_reversible_command ();
diff --git a/gtk2_ardour/editor_summary.cc b/gtk2_ardour/editor_summary.cc
index 5c2135a..6a2ba3b 100644
--- a/gtk2_ardour/editor_summary.cc
+++ b/gtk2_ardour/editor_summary.cc
@@ -143,28 +143,24 @@ EditorSummary::render (cairo_t* cr)
 	_start = theoretical_start > 0 ? theoretical_start : 0;
 	_end = _session->current_end_frame() + session_length * _overhang_fraction;
 
-	/* compute total height of all tracks */
-
-	int h = 0;
-	int max_height = 0;
-	for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
-		int const t = (*i)->effective_height ();
-		h += t;
-		max_height = max (max_height, t);
-	}
+	/* compute x and y scale */
 
 	if (_end != _start) {
 		_x_scale = static_cast<double> (_width) / (_end - _start);
 	} else {
 		_x_scale = 1;
 	}
-	_y_scale = static_cast<double> (_height) / h;
 
-	/* tallest a region should ever be in the summary, in pixels */
-	int const tallest_region_pixels = _height / 16;
+	double h = 0;
+	for (TrackViewList::const_iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
+		h += (*i)->effective_height ();
+	}
 
-	if (max_height * _y_scale > tallest_region_pixels) {
-		_y_scale = static_cast<double> (tallest_region_pixels) / max_height;
+	double vh = _editor->canvas_height() - _editor->get_canvas_timebars_vsize();
+	if (vh > h) {
+		_y_scale = _height / vh;
+	} else {
+		_y_scale = _height / h;
 	}
 
 	/* render regions */
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index 63852fd..cbd89dd 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -2107,8 +2107,17 @@ MidiRegionView::begin_resizing (bool /*at_front*/)
 	}
 }
 
+/** Update resizing notes while user drags.
+ * @param primary `primary' note for the drag; ie the one that is used as the reference in non-relative mode.
+ * @param at_front which end of the note (true == note on, false == note off)
+ * @param delta_x change in mouse position since the start of the drag 
+ * @param relative true if relative resizing is taking place, false if absolute resizing.  This only makes
+ * a difference when multiple notes are being resized; in relative mode, each note's length is changed by the
+ * amount of the drag.  In non-relative mode, all selected notes are set to have the same start or end point
+ * as the \a primary note.
+ */
 void
-MidiRegionView::update_resizing (bool at_front, double delta_x, bool relative)
+MidiRegionView::update_resizing (ArdourCanvas::CanvasNote* primary, bool at_front, double delta_x, bool relative)
 {
 	for (std::vector<NoteResizeData *>::iterator i = _resize_data.begin(); i != _resize_data.end(); ++i) {
 		SimpleRect* resize_rect = (*i)->resize_rect;
@@ -2119,15 +2128,13 @@ MidiRegionView::update_resizing (bool at_front, double delta_x, bool relative)
 			if (relative) {
 				current_x = canvas_note->x1() + delta_x;
 			} else {
-				// x is in track relative, transform it to region relative
-				current_x = delta_x - get_position_pixels();
+				current_x = primary->x1() + delta_x;
 			}
 		} else {
 			if (relative) {
 				current_x = canvas_note->x2() + delta_x;
 			} else {
-				// x is in track relative, transform it to region relative
-				current_x = delta_x - get_end_position_pixels ();
+				current_x = primary->x2() + delta_x;
 			}
 		}
 
@@ -2141,30 +2148,31 @@ MidiRegionView::update_resizing (bool at_front, double delta_x, bool relative)
 	}
 }
 
+
+/** Finish resizing notes when the user releases the mouse button.
+ *  Parameters the same as for \a update_resizing().
+ */
 void
-MidiRegionView::commit_resizing (bool at_front, double delta_x, bool relative)
+MidiRegionView::commit_resizing (ArdourCanvas::CanvasNote* primary, bool at_front, double delta_x, bool relative)
 {
 	start_diff_command(_("resize notes"));
 
 	for (std::vector<NoteResizeData *>::iterator i = _resize_data.begin(); i != _resize_data.end(); ++i) {
 		CanvasNote*  canvas_note = (*i)->canvas_note;
 		SimpleRect*  resize_rect = (*i)->resize_rect;
-		const double region_start = get_position_pixels();
 		double current_x;
 
 		if (at_front) {
 			if (relative) {
 				current_x = canvas_note->x1() + delta_x;
 			} else {
-				// x is in track relative, transform it to region relative
-				current_x = region_start + delta_x;
+				current_x = primary->x1() + delta_x;
 			}
 		} else {
 			if (relative) {
 				current_x = canvas_note->x2() + delta_x;
 			} else {
-				// x is in track relative, transform it to region relative
-				current_x = region_start + delta_x;
+				current_x = primary->x2() + delta_x;
 			}
 		}
 
diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h
index cb36015..1f2d539 100644
--- a/gtk2_ardour/midi_region_view.h
+++ b/gtk2_ardour/midi_region_view.h
@@ -219,20 +219,8 @@ class MidiRegionView : public RegionView
 	 */
 	void begin_resizing(bool at_front);
 
-	/** Update resizing notes while user drags.
-	 * @param at_front which end of the note (true == note on, false == note off)
-	 * @param x the difference in mouse motion, ie the motion difference if relative=true
-	 *           or the absolute mouse position (track-relative) if relative is false
-	 * @param relative true if relative resizing is taking place, false if absolute resizing
-	 */
-	void update_resizing(bool at_front, double x, bool relative);
-
-	/** Finish resizing notes when the user releases the mouse button.
-	 * @param at_front which end of the note (true == note on, false == note off)
-	 * @param event_x the absolute mouse position (track-relative)
-	 * @param relative true if relative resizing is taking place, false if absolute resizing
-	 */
-	void commit_resizing(bool at_front, double event_x, bool relative);
+	void update_resizing (ArdourCanvas::CanvasNote *, bool, double, bool);
+	void commit_resizing (ArdourCanvas::CanvasNote *, bool, double, bool);
 
 	/** Adjust the velocity on a note, and the selection if applicable.
 	 * @param velocity the relative or absolute velocity
diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc
index e51699d..e193f6d 100644
--- a/gtk2_ardour/midi_time_axis.cc
+++ b/gtk2_ardour/midi_time_axis.cc
@@ -387,6 +387,7 @@ MidiTimeAxisView::build_automation_action_menu ()
 		detach_menu (*controller_menu);
 	}
 
+	_channel_command_menu_map.clear ();
 	RouteTimeAxisView::build_automation_action_menu ();
 
 	MenuList& automation_items = automation_action_menu->items();
@@ -403,9 +404,9 @@ MidiTimeAxisView::build_automation_action_menu ()
 		   something about MIDI (!) would not expect to find them there.
 		*/
 
-		add_channel_command_menu_item (automation_items, _("Program Change"), MidiPgmChangeAutomation, MIDI_CMD_PGM_CHANGE);
-		add_channel_command_menu_item (automation_items, _("Bender"), MidiPitchBenderAutomation, MIDI_CMD_BENDER);
-		add_channel_command_menu_item (automation_items, _("Pressure"), MidiChannelPressureAutomation, MIDI_CMD_CHANNEL_PRESSURE);
+		add_channel_command_menu_item (automation_items, _("Program Change"), MidiPgmChangeAutomation, 0);
+		add_channel_command_menu_item (automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
+		add_channel_command_menu_item (automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
 		
 		/* now all MIDI controllers. Always offer the possibility that we will rebuild the controllers menu
 		   since it might need to be updated after a channel mode change or other change. Also detach it
@@ -494,9 +495,9 @@ MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
 						visible = true;
 					}
 				}
-				
+
 				CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
-				_parameter_menu_map[fully_qualified_param] = cmi;
+				_channel_command_menu_map[fully_qualified_param] = cmi;
 				cmi->set_active (visible);
 			}
 		}
@@ -527,7 +528,7 @@ MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
 				}
 				
 				CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
-				_parameter_menu_map[fully_qualified_param] = cmi;
+				_channel_command_menu_map[fully_qualified_param] = cmi;
 				cmi->set_active (visible);
 				
 				/* one channel only */
@@ -618,7 +619,7 @@ MidiTimeAxisView::build_controller_menu ()
 						}
 						
 						CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
-						_parameter_menu_map[fully_qualified_param] = cmi;
+						_controller_menu_map[fully_qualified_param] = cmi;
 						cmi->set_active (visible);
 					}
 				}
@@ -649,7 +650,7 @@ MidiTimeAxisView::build_controller_menu ()
 						}
 						
 						CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
-						_parameter_menu_map[fully_qualified_param] = cmi;
+						_controller_menu_map[fully_qualified_param] = cmi;
 						cmi->set_active (visible);
 						
 						/* one channel only */
@@ -791,7 +792,7 @@ MidiTimeAxisView::show_existing_automation ()
 	RouteTimeAxisView::show_existing_automation ();
 }
 
-/** Hide an automation track for the given parameter (pitch bend, channel pressure).
+/** Create an automation track for the given parameter (pitch bend, channel pressure).
  */
 void
 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
@@ -1080,6 +1081,7 @@ MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
 	/* TODO: Bender, PgmChange, Pressure */
 
 	/* invalidate the controller menu, so that we rebuilt it next time */
+	_controller_menu_map.clear ();
 	delete controller_menu;
 	controller_menu = 0;
 
@@ -1087,3 +1089,24 @@ MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
 		_route->gui_changed ("track_height", this);
 	}
 }
+
+Gtk::CheckMenuItem*
+MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
+{
+	Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
+	if (m) {
+		return m;
+	}
+
+	ParameterMenuMap::iterator i = _controller_menu_map.find (param);
+	if (i != _controller_menu_map.end()) {
+		return i->second;
+	}
+
+	i = _channel_command_menu_map.find (param);
+	if (i != _channel_command_menu_map.end()) {
+		return i->second;
+	}
+
+	return 0;
+}
diff --git a/gtk2_ardour/midi_time_axis.h b/gtk2_ardour/midi_time_axis.h
index aeb7ff1..e15167f 100644
--- a/gtk2_ardour/midi_time_axis.h
+++ b/gtk2_ardour/midi_time_axis.h
@@ -93,6 +93,8 @@ class MidiTimeAxisView : public RouteTimeAxisView
 
 	const MidiMultipleChannelSelector& channel_selector() { return _channel_selector; }
 
+	Gtk::CheckMenuItem* automation_child_menu_item (Evoral::Parameter);
+	
   private:
 	sigc::signal<void, std::string, std::string>  _midi_patch_settings_changed;
 
@@ -152,6 +154,11 @@ class MidiTimeAxisView : public RouteTimeAxisView
 	void add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask);
 	void extend_note_selection_region_view (RegionView*, uint8_t note, uint16_t chn_mask);
 	void toggle_note_selection_region_view (RegionView*, uint8_t note, uint16_t chn_mask);
+
+	/** parameter -> menu item map for the channel command items */
+	ParameterMenuMap _channel_command_menu_map;
+	/** parameter -> menu item map for the controller menu */
+	ParameterMenuMap _controller_menu_map;
 };
 
 #endif /* __ardour_midi_time_axis_h__ */
diff --git a/gtk2_ardour/rc_option_editor.cc b/gtk2_ardour/rc_option_editor.cc
index d90773b..83b3e49 100644
--- a/gtk2_ardour/rc_option_editor.cc
+++ b/gtk2_ardour/rc_option_editor.cc
@@ -713,6 +713,80 @@ private:
 	HScale _dpi_slider;
 };
 
+class BufferingOptions : public OptionEditorBox
+{
+public:
+	BufferingOptions (RCConfiguration* c) 
+                : _rc_config (c)
+		, _playback_adjustment (5, 1, 60, 1, 4)
+                , _capture_adjustment (5, 1, 60, 1, 4)
+                , _playback_slider (_playback_adjustment)
+		, _capture_slider (_capture_adjustment)
+	{
+		_playback_adjustment.set_value (_rc_config->get_audio_playback_buffer_seconds());
+
+		Label* l = manage (new Label (_("Playback (seconds of buffering):")));
+		l->set_name ("OptionsLabel");
+
+		_playback_slider.set_update_policy (UPDATE_DISCONTINUOUS);
+		HBox* h = manage (new HBox);
+		h->set_spacing (4);
+		h->pack_start (*l, false, false);
+		h->pack_start (_playback_slider, true, true);
+
+		_box->pack_start (*h, false, false);
+                
+		_capture_adjustment.set_value (_rc_config->get_audio_capture_buffer_seconds());
+
+		l = manage (new Label (_("Recording (seconds of buffering):")));
+		l->set_name ("OptionsLabel");
+
+		_capture_slider.set_update_policy (UPDATE_DISCONTINUOUS);
+		h = manage (new HBox);
+		h->set_spacing (4);
+		h->pack_start (*l, false, false);
+		h->pack_start (_capture_slider, true, true);
+
+		_box->pack_start (*h, false, false);
+                
+		_capture_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &BufferingOptions::capture_changed));
+		_playback_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &BufferingOptions::playback_changed));
+	}
+
+	void parameter_changed (string const & p)
+	{
+		if (p == "playback-buffer-seconds") {
+			_playback_adjustment.set_value (_rc_config->get_audio_playback_buffer_seconds());
+		} else if (p == "capture-buffer-seconds") {
+			_capture_adjustment.set_value (_rc_config->get_audio_capture_buffer_seconds());
+                }
+	}
+
+	void set_state_from_config ()
+	{
+		parameter_changed ("playback-buffer-seconds");
+		parameter_changed ("capture-buffer-seconds");
+	}
+
+private:
+
+	void playback_changed ()
+	{
+		_rc_config->set_audio_playback_buffer_seconds ((long) _playback_adjustment.get_value());
+	}
+
+	void capture_changed ()
+	{
+		_rc_config->set_audio_capture_buffer_seconds ((long) _capture_adjustment.get_value());
+	}
+
+	RCConfiguration* _rc_config;
+	Adjustment _playback_adjustment;
+	Adjustment _capture_adjustment;
+	HScale _playback_slider;
+	HScale _capture_slider;
+};
+
 class ControlSurfacesOptions : public OptionEditorBox
 {
 public:
@@ -1102,6 +1176,10 @@ RCOptionEditor::RCOptionEditor ()
 
 	/* AUDIO */
 
+	add_option (_("Audio"), new OptionEditorHeading (_("Buffering")));
+
+	add_option (_("Audio"), new BufferingOptions (_rc_config));
+
 	add_option (_("Audio"), new OptionEditorHeading (_("Monitoring")));
 
 	add_option (_("Audio"),
diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc
index 9ec6048..49c49a3 100644
--- a/gtk2_ardour/route_time_axis.cc
+++ b/gtk2_ardour/route_time_axis.cc
@@ -264,6 +264,7 @@ RouteTimeAxisView::post_construct ()
 
 	update_diskstream_display ();
 
+	_subplugin_menu_map.clear ();
 	subplugin_menu.items().clear ();
 	_route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
 	_route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
@@ -397,6 +398,7 @@ RouteTimeAxisView::build_automation_action_menu ()
 
 	detach_menu (subplugin_menu);
 
+	_main_automation_menu_map.clear ();
 	delete automation_action_menu;
 	automation_action_menu = new Menu;
 
@@ -436,7 +438,7 @@ RouteTimeAxisView::build_display_menu ()
 	MenuList& items = display_menu->items();
 	display_menu->set_name ("ArdourContextMenu");
 
-	items.push_back (MenuElem (_("Color"), sigc::mem_fun(*this, &RouteTimeAxisView::select_track_color)));
+	items.push_back (MenuElem (_("Color..."), sigc::mem_fun(*this, &RouteTimeAxisView::select_track_color)));
 
 	items.push_back (SeparatorElem());
 
@@ -1689,8 +1691,9 @@ RouteTimeAxisView::show_existing_automation ()
 			i->second->get_state_node()->add_property ("shown", X_("yes"));
 
 			Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
-			assert (menu);
-			menu->set_active(true);
+			if (menu) {
+				menu->set_active(true);
+			}
 		}
 	}
 
@@ -2008,7 +2011,7 @@ RouteTimeAxisView::add_processor_to_subplugin_menu (boost::weak_ptr<Processor> p
 		items.push_back (CheckMenuElem (name));
 		mitem = dynamic_cast<CheckMenuItem*> (&items.back());
 
-		_parameter_menu_map[*i] = mitem;
+		_subplugin_menu_map[*i] = mitem;
 
 		if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
 			mitem->set_active(true);
@@ -2089,6 +2092,7 @@ RouteTimeAxisView::processors_changed (RouteProcessorChange c)
 		(*i)->valid = false;
 	}
 
+	_subplugin_menu_map.clear ();
 	subplugin_menu.items().clear ();
 
 	_route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
@@ -2373,10 +2377,15 @@ RouteTimeAxisView::set_button_names ()
 Gtk::CheckMenuItem*
 RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
 {
-	ParameterMenuMap::iterator i = _parameter_menu_map.find (param);
-	if (i == _parameter_menu_map.end()) {
-		return 0;
+	ParameterMenuMap::iterator i = _main_automation_menu_map.find (param);
+	if (i != _main_automation_menu_map.end()) {
+		return i->second;
+	}
+	
+	i = _subplugin_menu_map.find (param);
+	if (i != _subplugin_menu_map.end()) {
+		return i->second;
 	}
 
-	return i->second;
+	return 0;
 }
diff --git a/gtk2_ardour/route_time_axis.h b/gtk2_ardour/route_time_axis.h
index 8f569d8..576c353 100644
--- a/gtk2_ardour/route_time_axis.h
+++ b/gtk2_ardour/route_time_axis.h
@@ -126,7 +126,7 @@ public:
 	AutomationTracks automation_tracks() { return _automation_tracks; }
 
 	boost::shared_ptr<AutomationTimeAxisView> automation_child(Evoral::Parameter param);
-	Gtk::CheckMenuItem* automation_child_menu_item (Evoral::Parameter);
+	virtual Gtk::CheckMenuItem* automation_child_menu_item (Evoral::Parameter);
 	
 	std::string         name() const;
 	StreamView*         view() const { return _view; }
@@ -287,7 +287,10 @@ protected:
 
 	AutomationTracks _automation_tracks;
 	typedef std::map<Evoral::Parameter, Gtk::CheckMenuItem*> ParameterMenuMap;
-	ParameterMenuMap _parameter_menu_map;
+	/** parameter -> menu item map for the main automation menu */
+	ParameterMenuMap _main_automation_menu_map;
+	/** parameter -> menu item map for the plugin automation menu */
+	ParameterMenuMap _subplugin_menu_map;
 
 	void post_construct ();
 
diff --git a/libs/ardour/amp.cc b/libs/ardour/amp.cc
index ceb593f..a739b59 100644
--- a/libs/ardour/amp.cc
+++ b/libs/ardour/amp.cc
@@ -167,9 +167,8 @@ Amp::apply_gain (BufferSet& bufs, nframes_t nframes, gain_t initial, gain_t targ
 			Evoral::MIDIEvent<MidiBuffer::TimeType> ev = *m;
 
 			if (ev.is_note_on()) {
-				gain_t scale = delta * (ev.time()/nframes);
-				std::cerr << "scale by " << scale << " for " << ev.time() << " of " << nframes << std::endl;
-				ev.scale_velocity (scale);
+				gain_t scale = delta * (ev.time()/(double) nframes);
+				ev.scale_velocity (initial+scale);
 			}
 		}
 	}
diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h
index 6cf064a..54ddbea 100644
--- a/libs/ardour/ardour/audio_diskstream.h
+++ b/libs/ardour/ardour/audio_diskstream.h
@@ -28,6 +28,8 @@
 
 #include <time.h>
 
+#include <boost/utility.hpp>
+
 #include "pbd/fastlog.h"
 #include "pbd/ringbufferNPT.h"
 #include "pbd/stateful.h"
@@ -179,9 +181,12 @@ class AudioDiskstream : public Diskstream
 
   private:
 
-	struct ChannelInfo {
+	struct ChannelInfo : public boost::noncopyable {
 
-		ChannelInfo (nframes_t buffer_size, nframes_t speed_buffer_size, nframes_t wrap_buffer_size);
+		ChannelInfo (nframes_t playback_buffer_size, 
+                             nframes_t capture_buffer_size,
+                             nframes_t speed_buffer_size, 
+                             nframes_t wrap_buffer_size);
 		~ChannelInfo ();
 
 		Sample     *playback_wrap_buffer;
@@ -211,6 +216,9 @@ class AudioDiskstream : public Diskstream
 		RingBufferNPT<CaptureTransition> * capture_transition_buf;
 		// the following are used in the butler thread only
 		nframes_t                     curr_capture_cnt;
+
+                void resize_playback (nframes_t);
+                void resize_capture (nframes_t);
 	};
 
 	typedef std::vector<ChannelInfo*> ChannelList;
@@ -250,6 +258,9 @@ class AudioDiskstream : public Diskstream
 	void setup_destructive_playlist ();
 	void use_destructive_playlist ();
 
+        void adjust_playback_buffering ();
+        void adjust_capture_buffering ();
+
 	void engage_record_enable ();
 	void disengage_record_enable ();
 
diff --git a/libs/ardour/ardour/butler.h b/libs/ardour/ardour/butler.h
index e3760a8..6ad96dc 100644
--- a/libs/ardour/ardour/butler.h
+++ b/libs/ardour/ardour/butler.h
@@ -54,7 +54,8 @@ class Butler : public SessionHandleRef
 	float read_data_rate() const; ///< in usec
 	float write_data_rate() const;
 
-	uint32_t audio_diskstream_buffer_size() const { return audio_dstream_buffer_size; }
+	nframes_t audio_diskstream_capture_buffer_size() const { return audio_dstream_capture_buffer_size; }
+	nframes_t audio_diskstream_playback_buffer_size() const { return audio_dstream_playback_buffer_size; }
 	uint32_t midi_diskstream_buffer_size()  const { return midi_dstream_buffer_size; }
 
 	static void* _thread_work(void *arg);
@@ -75,12 +76,14 @@ class Butler : public SessionHandleRef
 	bool         should_run;
 	mutable gint should_do_transport_work;
 	int          request_pipe[2];
-	uint32_t     audio_dstream_buffer_size;
+	nframes_t    audio_dstream_capture_buffer_size;
+	nframes_t    audio_dstream_playback_buffer_size;
 	uint32_t     midi_dstream_buffer_size;
 	RingBuffer<CrossThreadPool*> pool_trash;
 
 private:
 	void empty_pool_trash ();
+        void config_changed (std::string);
 };
 
 } // namespace ARDOUR
diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h
index 766f9ec..f466889 100644
--- a/libs/ardour/ardour/midi_diskstream.h
+++ b/libs/ardour/ardour/midi_diskstream.h
@@ -165,6 +165,12 @@ class MidiDiskstream : public Diskstream
 	void get_input_sources ();
 	void set_align_style_from_io();
 
+        /* fixed size buffers per instance of ardour for now (non-dynamic)
+         */
+
+        void adjust_playback_buffering () {}
+        void adjust_capture_buffering () {}
+
 	void engage_record_enable ();
 	void disengage_record_enable ();
 
diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h
index 5d5bdc0..d181bea 100644
--- a/libs/ardour/ardour/midi_track.h
+++ b/libs/ardour/ardour/midi_track.h
@@ -53,7 +53,7 @@ public:
 
 	void freeze_me (InterThreadInfo&);
 	void unfreeze ();
-
+        
 	boost::shared_ptr<Region> bounce (InterThreadInfo&);
 	boost::shared_ptr<Region>  bounce_range (
 			nframes_t start, nframes_t end, InterThreadInfo&, bool enable_processing);
diff --git a/libs/ardour/ardour/public_diskstream.h b/libs/ardour/ardour/public_diskstream.h
index 90ca030..c31e88a 100755
--- a/libs/ardour/ardour/public_diskstream.h
+++ b/libs/ardour/ardour/public_diskstream.h
@@ -72,6 +72,8 @@ public:
 	virtual void set_align_style (AlignStyle) = 0;
 	virtual int use_copy_playlist () = 0;
 	virtual int use_new_playlist () = 0;
+        virtual void adjust_playback_buffering () = 0;
+        virtual void adjust_capture_buffering () = 0;
 	
 };
 
diff --git a/libs/ardour/ardour/rc_configuration_vars.h b/libs/ardour/ardour/rc_configuration_vars.h
index 158f84a..bbf3736 100644
--- a/libs/ardour/ardour/rc_configuration_vars.h
+++ b/libs/ardour/ardour/rc_configuration_vars.h
@@ -51,7 +51,8 @@ CONFIG_VARIABLE (RemoteModel, remote_model, "remote-model", MixerOrdered)
 
 CONFIG_VARIABLE (uint32_t, minimum_disk_io_bytes,  "minimum-disk-io-bytes", 1024 * 256)
 CONFIG_VARIABLE (float, midi_readahead,  "midi-readahead", 1.0)
-CONFIG_VARIABLE (float, audio_track_buffer_seconds, "track-buffer-seconds", 5.0)
+CONFIG_VARIABLE (float, audio_capture_buffer_seconds, "capture-buffer-seconds", 5.0)
+CONFIG_VARIABLE (float, audio_playback_buffer_seconds, "playback-buffer-seconds", 5.0)
 CONFIG_VARIABLE (float, midi_track_buffer_seconds, "midi-track-buffer-seconds", 1.0)
 CONFIG_VARIABLE (uint32_t, disk_choice_space_threshold,  "disk-choice-space-threshold", 57600000)
 CONFIG_VARIABLE (bool, auto_analyse_audio, "auto-analyse-audio", false)
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index d1362b3..f7692e0 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -299,6 +299,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 	void allow_auto_play (bool yn);
 	void request_transport_speed (double speed);
 	void request_overwrite_buffer (Track *);
+	void adjust_playback_buffering();
+	void adjust_capture_buffering();
 	void request_track_speed (Track *, double speed);
 	void request_input_change_handling ();
 
@@ -776,7 +778,9 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 		PostTransportReverse            = 0x10000,
 		PostTransportInputChange        = 0x20000,
 		PostTransportCurveRealloc       = 0x40000,
-		PostTransportClearSubstate      = 0x80000
+		PostTransportClearSubstate      = 0x80000,
+		PostTransportAdjustPlaybackBuffering  = 0x100000,
+		PostTransportAdjustCaptureBuffering   = 0x200000
 	};
 
 	enum SlaveState {
@@ -1028,6 +1032,9 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 	void set_post_transport_work (PostTransportWork ptw) { g_atomic_int_set (&_post_transport_work, (gint) ptw); }
 	void add_post_transport_work (PostTransportWork ptw);
 
+        void schedule_playback_buffering_adjustment ();
+        void schedule_capture_buffering_adjustment ();
+
 	uint32_t    cumulative_rf_motion;
 	uint32_t    rf_scale;
 
@@ -1437,6 +1444,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 	std::list<boost::shared_ptr<Diskstream> > _diskstreams_2X;
 
 	void add_session_range_location (nframes_t, nframes_t);
+
+
 };
 
 } // namespace ARDOUR
diff --git a/libs/ardour/ardour/session_event.h b/libs/ardour/ardour/session_event.h
index 726c5be..eac27be 100644
--- a/libs/ardour/ardour/session_event.h
+++ b/libs/ardour/ardour/session_event.h
@@ -34,6 +34,8 @@ struct SessionEvent {
 	    InputConfigurationChange,
 	    SetPlayAudioRange,
 	    RealTimeOperation,
+            AdjustPlaybackBuffering,
+            AdjustCaptureBuffering,
 
 	    /* only one of each of these events can be queued at any one time */
 	    
diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h
index a40b829..ac948f1 100644
--- a/libs/ardour/ardour/track.h
+++ b/libs/ardour/ardour/track.h
@@ -138,6 +138,8 @@ class Track : public Route, public PublicDiskstream
 	void set_align_style (AlignStyle);
 	int use_copy_playlist ();
 	int use_new_playlist ();
+        void adjust_playback_buffering ();
+        void adjust_capture_buffering ();
 
 	PBD::Signal0<void> DiskstreamChanged;
 	PBD::Signal0<void> FreezeChange;
diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc
index 91ca6a8..b3204c3 100644
--- a/libs/ardour/audio_diskstream.cc
+++ b/libs/ardour/audio_diskstream.cc
@@ -2056,8 +2056,10 @@ int
 AudioDiskstream::add_channel_to (boost::shared_ptr<ChannelList> c, uint32_t how_many)
 {
 	while (how_many--) {
-		c->push_back (new ChannelInfo(_session.butler()->audio_diskstream_buffer_size(), speed_buffer_size, wrap_buffer_size));
-		interpolation.add_channel_to (_session.butler()->audio_diskstream_buffer_size(), speed_buffer_size);
+		c->push_back (new ChannelInfo(_session.butler()->audio_diskstream_playback_buffer_size(), 
+                                              _session.butler()->audio_diskstream_capture_buffer_size(),
+                                              speed_buffer_size, wrap_buffer_size));
+		interpolation.add_channel_to (_session.butler()->audio_diskstream_playback_buffer_size(), speed_buffer_size);
 	}
 
 	_n_channels.set(DataType::AUDIO, c->size());
@@ -2295,7 +2297,27 @@ AudioDiskstream::can_become_destructive (bool& requires_bounce) const
 	return true;
 }
 
-AudioDiskstream::ChannelInfo::ChannelInfo (nframes_t bufsize, nframes_t speed_size, nframes_t wrap_size)
+void 
+AudioDiskstream::adjust_playback_buffering ()
+{
+	boost::shared_ptr<ChannelList> c = channels.reader();
+
+	for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
+                (*chan)->resize_playback (_session.butler()->audio_diskstream_playback_buffer_size());
+        }
+}
+
+void 
+AudioDiskstream::adjust_capture_buffering ()
+{
+	boost::shared_ptr<ChannelList> c = channels.reader();
+
+	for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) {
+                (*chan)->resize_capture (_session.butler()->audio_diskstream_capture_buffer_size());
+        }
+}
+
+AudioDiskstream::ChannelInfo::ChannelInfo (nframes_t playback_bufsize, nframes_t capture_bufsize, nframes_t speed_size, nframes_t wrap_size)
 {
 	peak_power = 0.0f;
 	source = 0;
@@ -2307,8 +2329,8 @@ AudioDiskstream::ChannelInfo::ChannelInfo (nframes_t bufsize, nframes_t speed_si
 	playback_wrap_buffer = new Sample[wrap_size];
 	capture_wrap_buffer = new Sample[wrap_size];
 
-	playback_buf = new RingBufferNPT<Sample> (bufsize);
-	capture_buf = new RingBufferNPT<Sample> (bufsize);
+	playback_buf = new RingBufferNPT<Sample> (playback_bufsize);
+	capture_buf = new RingBufferNPT<Sample> (capture_bufsize);
 	capture_transition_buf = new RingBufferNPT<CaptureTransition> (256);
 
 	/* touch the ringbuffer buffers, which will cause
@@ -2322,6 +2344,22 @@ AudioDiskstream::ChannelInfo::ChannelInfo (nframes_t bufsize, nframes_t speed_si
 	memset (capture_transition_buf->buffer(), 0, sizeof (CaptureTransition) * capture_transition_buf->bufsize());
 }
 
+void
+AudioDiskstream::ChannelInfo::resize_playback (nframes_t playback_bufsize)
+{
+        delete playback_buf;
+	playback_buf = new RingBufferNPT<Sample> (playback_bufsize);
+	memset (playback_buf->buffer(), 0, sizeof (Sample) * playback_buf->bufsize());
+}
+
+void
+AudioDiskstream::ChannelInfo::resize_capture (nframes_t capture_bufsize)
+{
+        delete capture_buf;
+	capture_buf = new RingBufferNPT<Sample> (capture_bufsize);
+	memset (capture_buf->buffer(), 0, sizeof (Sample) * capture_buf->bufsize());
+}
+
 AudioDiskstream::ChannelInfo::~ChannelInfo ()
 {
         write_source.reset ();
@@ -2344,3 +2382,4 @@ AudioDiskstream::ChannelInfo::~ChannelInfo ()
 	delete capture_transition_buf;
 	capture_transition_buf = 0;
 }
+
diff --git a/libs/ardour/audio_port.cc b/libs/ardour/audio_port.cc
index a75f7d7..71ec7c6 100644
--- a/libs/ardour/audio_port.cc
+++ b/libs/ardour/audio_port.cc
@@ -98,8 +98,8 @@ AudioPort::get_audio_buffer (nframes_t nframes, nframes_t offset)
 }
 
 size_t
-AudioPort::raw_buffer_size(nframes_t nframes) const
+AudioPort::raw_buffer_size (nframes_t nframes) const
 {
-	return nframes * sizeof(float);
+	return nframes * sizeof (Sample);
 }
 
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index fcd2113..fcc6da2 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -732,3 +732,4 @@ AudioTrack::write_source (uint32_t n)
 	assert (ds);
 	return ds->write_source (n);
 }
+
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index a16f268..d2cf8d1 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -232,6 +232,15 @@ AudioEngine::start ()
 		}
 
 		_raw_buffer_sizes[DataType::AUDIO] = blocksize * sizeof(float);
+
+                jack_port_t* midi_port = jack_port_register (_priv_jack, "m", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
+                if (!midi_port) {
+                        error << _("Cannot create temporary MIDI port to determine MIDI buffer size") << endmsg;
+                } else {
+                        _raw_buffer_sizes[DataType::MIDI] = jack_midi_max_event_size (jack_port_get_buffer(midi_port, blocksize));
+                        cerr << "MIDI port buffers = " << _raw_buffer_sizes[DataType::MIDI] << endl;
+                        jack_port_unregister (_priv_jack, midi_port);
+                }
 	}
 
 	return _running ? 0 : -1;
@@ -420,6 +429,7 @@ AudioEngine::process_thread ()
                 jack_nframes_t nframes = jack_cycle_wait (_jack);
 
                 if (process_callback (nframes)) {
+                        cerr << "--- process\n";
                         return 0;
                 }
 
@@ -583,16 +593,40 @@ AudioEngine::_bufsize_callback (nframes_t nframes, void *arg)
 int
 AudioEngine::jack_bufsize_callback (nframes_t nframes)
 {
+        bool need_midi_size = true;
+        bool need_audio_size = true;
+
 	_buffer_size = nframes;
-	_raw_buffer_sizes[DataType::AUDIO] = nframes * sizeof(float);
-	cout << "FIXME: Assuming maximum MIDI buffer size " << nframes * 4 << "bytes" << endl;
-	_raw_buffer_sizes[DataType::MIDI] = nframes * 4;
 	_usecs_per_cycle = (int) floor ((((double) nframes / frame_rate())) * 1000000.0);
 	last_monitor_check = 0;
 
 	boost::shared_ptr<Ports> p = ports.reader();
 
+        /* crude guesses, see below where we try to get the right answers.
+
+           Note that our guess for MIDI deliberatey tries to overestimate
+           by a little. It would be nicer if we could get the actual
+           size from a port, but we have to use this estimate in the 
+           event that there are no MIDI ports currently. If there are
+           the value will be adjusted below.
+         */
+
+        _raw_buffer_sizes[DataType::AUDIO] = nframes * sizeof (Sample);
+        _raw_buffer_sizes[DataType::MIDI] = nframes * 4 - (nframes/2);
+
 	for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
+
+                if (need_audio_size && (*i)->type() == DataType::AUDIO) {
+                        _raw_buffer_sizes[DataType::AUDIO] = (*i)->raw_buffer_size (nframes);
+                        need_audio_size = false;
+                }
+                
+                        
+                if (need_midi_size && (*i)->type() == DataType::MIDI) {
+                        _raw_buffer_sizes[DataType::MIDI] = (*i)->raw_buffer_size (nframes);
+                        need_midi_size = false;
+                }
+                
 		(*i)->reset();
 	}
 
diff --git a/libs/ardour/butler.cc b/libs/ardour/butler.cc
index 9847d55..1efca35 100644
--- a/libs/ardour/butler.cc
+++ b/libs/ardour/butler.cc
@@ -43,12 +43,15 @@ namespace ARDOUR {
 Butler::Butler(Session& s)
 	: SessionHandleRef (s)
 	, thread(0)
-	, audio_dstream_buffer_size(0)
+	, audio_dstream_capture_buffer_size(0)
+	, audio_dstream_playback_buffer_size(0)
 	, midi_dstream_buffer_size(0)
 	, pool_trash(16)
 {
 	g_atomic_int_set(&should_do_transport_work, 0);
 	SessionEvent::pool->set_trash (&pool_trash);
+
+        Config->ParameterChanged.connect_same_thread (*this, boost::bind (&Butler::config_changed, this, _1));
 }
 
 Butler::~Butler()
@@ -56,13 +59,27 @@ Butler::~Butler()
 	terminate_thread ();
 }
 
+void
+Butler::config_changed (std::string p)
+{
+        if (p == "playback-buffer-seconds") {
+                /* size is in Samples, not bytes */
+                audio_dstream_playback_buffer_size = (uint32_t) floor (Config->get_audio_playback_buffer_seconds() * _session.frame_rate());
+                _session.adjust_playback_buffering ();
+        } else if (p == "capture-buffer-seconds") {
+                audio_dstream_capture_buffer_size = (uint32_t) floor (Config->get_audio_capture_buffer_seconds() * _session.frame_rate());
+                _session.adjust_capture_buffering ();
+        }
+}
+
 int
 Butler::start_thread()
 {
 	const float rate = (float)_session.frame_rate();
 
 	/* size is in Samples, not bytes */
-	audio_dstream_buffer_size = (uint32_t) floor (Config->get_audio_track_buffer_seconds() * rate);
+	audio_dstream_capture_buffer_size = (uint32_t) floor (Config->get_audio_capture_buffer_seconds() * rate);
+	audio_dstream_playback_buffer_size = (uint32_t) floor (Config->get_audio_playback_buffer_seconds() * rate);
 
 	/* size is in bytes
 	 * XXX: Jack needs to tell us the MIDI buffer size
@@ -72,7 +89,7 @@ Butler::start_thread()
 
 	MidiDiskstream::set_readahead_frames ((nframes_t)(Config->get_midi_readahead() * rate));
 
-	Crossfade::set_buffer_size (audio_dstream_buffer_size);
+	Crossfade::set_buffer_size (audio_dstream_playback_buffer_size);
 
 	should_run = false;
 
diff --git a/libs/ardour/delivery.cc b/libs/ardour/delivery.cc
index d815a06..cb8dc53 100644
--- a/libs/ardour/delivery.cc
+++ b/libs/ardour/delivery.cc
@@ -446,7 +446,7 @@ Delivery::flush (nframes_t nframes, nframes64_t time)
 	/* io_lock, not taken: function must be called from Session::process() calltree */
 
 	PortSet& ports (_output->ports());
-
+        
 	for (PortSet::iterator i = ports.begin(); i != ports.end(); ++i) {
 		(*i).flush_buffers (nframes, time, _output_offset);
 	}
diff --git a/libs/ardour/graph.cc b/libs/ardour/graph.cc
index 4cb8d56..5e62ba0 100644
--- a/libs/ardour/graph.cc
+++ b/libs/ardour/graph.cc
@@ -220,7 +220,7 @@ Graph::rechain (boost::shared_ptr<RouteList> routelist)
 
         pthread_mutex_lock (&_swap_mutex);
         int chain = _setup_chain;
-        printf ("============== setup %d\n", chain);
+        DEBUG_TRACE (DEBUG::Graph, string_compose ("============== setup %1\n", chain));
         // set all refcounts to 0;
 
         _init_finished_refcount[chain] = 0;
@@ -393,21 +393,21 @@ Graph::dump (int chain)
 
         chain = _pending_chain;
 
-        printf ("--------------------------------------------Graph dump:\n" );
+        DEBUG_TRACE (DEBUG::Graph, "--------------------------------------------Graph dump:\n");
         for (ni=_nodes_rt[chain].begin(); ni!=_nodes_rt[chain].end(); ni++) {
                 boost::shared_ptr<Route> rp = boost::dynamic_pointer_cast<Route>( *ni);
-                printf ("GraphNode: %s  refcount: %d\n", rp->name().c_str(), (*ni)->_init_refcount[chain] );
+                DEBUG_TRACE (DEBUG::Graph, string_compose ("GraphNode: %1  refcount: %2\n", rp->name().c_str(), (*ni)->_init_refcount[chain]));
                 for (ai=(*ni)->_activation_set[chain].begin(); ai!=(*ni)->_activation_set[chain].end(); ai++) {
-                        printf ("  triggers: %s\n", boost::dynamic_pointer_cast<Route>(*ai)->name().c_str() );
+                        DEBUG_TRACE (DEBUG::Graph, string_compose ("  triggers: %1\n", boost::dynamic_pointer_cast<Route>(*ai)->name().c_str()));
                 }
         }
 
-        printf ("------------- trigger list:\n" );
+        DEBUG_TRACE (DEBUG::Graph, "------------- trigger list:\n");
         for (ni=_init_trigger_list[chain].begin(); ni!=_init_trigger_list[chain].end(); ni++) {
-                printf ("GraphNode: %s  refcount: %d\n", boost::dynamic_pointer_cast<Route>(*ni)->name().c_str(), (*ni)->_init_refcount[chain] );
+                DEBUG_TRACE (DEBUG::Graph, string_compose ("GraphNode: %1  refcount: %2\n", boost::dynamic_pointer_cast<Route>(*ni)->name().c_str(), (*ni)->_init_refcount[chain]));
         }
 
-        printf ("final activation refcount: %d\n", _init_finished_refcount[chain] );
+        DEBUG_TRACE (DEBUG::Graph, string_compose ("final activation refcount: %1\n", _init_finished_refcount[chain]));
 #endif
 }
 
diff --git a/libs/ardour/midi_buffer.cc b/libs/ardour/midi_buffer.cc
index cbf7603..8299d81 100644
--- a/libs/ardour/midi_buffer.cc
+++ b/libs/ardour/midi_buffer.cc
@@ -18,11 +18,17 @@
 */
 
 #include <iostream>
+
 #include "pbd/malign.h"
+#include "pbd/compose.h"
+#include "pbd/debug.h"
+
+#include "ardour/debug.h"
 #include "ardour/midi_buffer.h"
 
 using namespace std;
 using namespace ARDOUR;
+using namespace PBD;
 
 // FIXME: mirroring for MIDI buffers?
 MidiBuffer::MidiBuffer(size_t capacity)
@@ -93,7 +99,10 @@ MidiBuffer::read_from (const Buffer& src, nframes_t nframes, nframes_t dst_offse
 		const Evoral::MIDIEvent<TimeType> ev(*i, false);
 		if (ev.time() >= src_offset && ev.time() < (nframes+src_offset)) {
 			push_back (ev);
-		}
+		} else {
+                        cerr << "MIDI event @ " <<  ev.time() << " skipped, not within range " << src_offset << " .. " 
+                             << (nframes + src_offset) << endl;
+                }
 	}
 
 	_silent = src.silent();
@@ -128,7 +137,7 @@ MidiBuffer::push_back(const Evoral::MIDIEvent<TimeType>& ev)
 		cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
 		return false;
 	}
-
+        
 	if (!Evoral::midi_event_is_valid(ev.buffer(), ev.size())) {
 		cerr << "WARNING: MidiBuffer ignoring illegal MIDI event" << endl;
 		return false;
@@ -147,8 +156,22 @@ bool
 MidiBuffer::push_back(TimeType time, size_t size, const uint8_t* data)
 {
 	const size_t stamp_size = sizeof(TimeType);
-	/*cerr << "MidiBuffer: pushing event @ " << ev.time()
-		<< " size = " << ev.size() << endl;*/
+
+#ifndef NDEBUG
+                DEBUG_STR_DECL(a);
+                DEBUG_STR_APPEND(a, string_compose ("midibuffer %1 push event @ %2 sz %3 ", this, time, size));
+		for (size_t i=0; i < size; ++i) {
+			DEBUG_STR_APPEND(a,hex);
+			DEBUG_STR_APPEND(a,"0x");
+			DEBUG_STR_APPEND(a,(int)data[i]);
+                        DEBUG_STR_APPEND(a,' ');
+		}
+                DEBUG_STR_APPEND(a,'\n');
+                DEBUG_TRACE (DEBUG::MidiIO, DEBUG_STR(a).str());
+#endif
+
+	// cerr << "MidiBuffer: pushing event @ " << time
+        // << " size = " << size << endl;
 
 	if (_size + stamp_size + size >= _capacity) {
 		cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
@@ -302,10 +325,12 @@ MidiBuffer::merge_in_place(const MidiBuffer &other)
 			++them;
 		}
 
+#if 0                
 		if (us != end())
 			cerr << "us @ " << (*us).time() << endl;
 		if (them != other.end())
 			cerr << "them @ " << (*them).time() << endl;
+#endif
 
 		if (sz) {
 			assert(src >= 0);
@@ -342,7 +367,7 @@ MidiBuffer::merge_in_place(const MidiBuffer &other)
 	size_t test_final_count = 0;
 	test_time = 0;
 	for (iterator i = begin(); i != end(); ++i) {
-		cerr << "CHECK " << test_final_count << " / " << test_us_count + test_them_count << endl;
+		// cerr << "CHECK " << test_final_count << " / " << test_us_count + test_them_count << endl;
 		assert(Evoral::midi_event_is_valid((*i).buffer(), (*i).size()));
 		assert((*i).time() >= test_time);
 		test_time = (*i).time();
diff --git a/libs/ardour/midi_playlist.cc b/libs/ardour/midi_playlist.cc
index eec0cde..89b5914 100644
--- a/libs/ardour/midi_playlist.cc
+++ b/libs/ardour/midi_playlist.cc
@@ -163,11 +163,11 @@ MidiPlaylist::read (MidiRingBuffer<nframes_t>& dst, nframes_t start, nframes_t d
 				DEBUG_TRACE (DEBUG::MidiPlaylistIO, "\tBEFORE: new tracker\n");
 			} else {
 				tracker = t->second;
-				DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\tBEFORE: tracker says there are %1 on notes", tracker->on()));
+				DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\tBEFORE: tracker says there are %1 on notes\n", tracker->on()));
 			}
 
 			mr->read_at (dst, start, dur, chan_n, _note_mode, tracker);
-			DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\tAFTER: tracker says there are %1 on notes", tracker->on()));
+			DEBUG_TRACE (DEBUG::MidiPlaylistIO, string_compose ("\tAFTER: tracker says there are %1 on notes\n", tracker->on()));
 
 			if (new_tracker) {
 				pair<Region*,MidiStateTracker*> newpair;
diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc
index 8dddc39..40cb48f 100644
--- a/libs/ardour/midi_port.cc
+++ b/libs/ardour/midi_port.cc
@@ -137,8 +137,14 @@ MidiPort::flush_buffers (nframes_t nframes, nframes64_t time, nframes_t offset)
 			assert(ev.time() < (nframes+offset+_port_offset));
 
 			if (ev.time() >= offset + _port_offset) {
-				jack_midi_event_write (jack_buffer, (jack_nframes_t) ev.time(), ev.buffer(), ev.size());
-			}
+				if (jack_midi_event_write (jack_buffer, (jack_nframes_t) ev.time(), ev.buffer(), ev.size()) != 0) {
+                                        cerr << "write failed, drop flushed note off on the floor, time " << ev.time() << " > " << offset << " + " << _port_offset 
+                                             << endl;			
+                                }
+                        } else {
+                                cerr << "drop flushed note off on the floor, time " << ev.time() << " > " << offset << " + " << _port_offset 
+                                     << endl;
+                        }
 		}
 	}
 }
diff --git a/libs/ardour/midi_ring_buffer.cc b/libs/ardour/midi_ring_buffer.cc
index e8ae9bb..2999621 100644
--- a/libs/ardour/midi_ring_buffer.cc
+++ b/libs/ardour/midi_ring_buffer.cc
@@ -50,7 +50,7 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes
 
 		this->full_peek(sizeof(T), (uint8_t*)&ev_time);
 
-		if (ev_time > end) {
+		if (ev_time >= end) {
 			DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB event @ %1 past end @ %2\n", ev_time, end));
 			break;
 		} else if (ev_time < start) {
@@ -70,7 +70,7 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes
 		if (ev_type == LoopEventType) {
 			/*ev_time -= start;
 			  ev_time += offset;*/
-			// cerr << "MRB loop boundary @ " << ev_time << endl;
+			cerr << "MRB loop boundary @ " << ev_time << endl;
 
 			// Return without reading data or writing to buffer (loop events have no data)
 			// FIXME: This is not correct, loses events after the loop this cycle
@@ -98,7 +98,7 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes
 		// write the timestamp to address (write_loc - 1)
 		uint8_t* write_loc = dst.reserve(ev_time, ev_size);
 		if (write_loc == NULL) {
-			// cerr << "MRB: Unable to reserve space in buffer, event skipped";
+			cerr << "MRB: Unable to reserve space in buffer, event skipped";
 			this->skip (ev_size); // Advance read pointer to next event
 			continue;
 		}
@@ -107,15 +107,16 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, nframes_t start, nframes_t end, nframes
 		success = read_contents (ev_size, write_loc);
 
 #ifndef NDEBUG
-		DEBUG_TRACE (DEBUG::MidiDiskstreamIO, "wrote MidiEvent to Buffer: ");
+                DEBUG_STR_DECL(a);
+                DEBUG_STR_APPEND(a, string_compose ("wrote MidiEvent to Buffer (time=%1, start=%2 offset=%3)", ev_time, start, offset));
 		for (size_t i=0; i < ev_size; ++i) {
-			DEBUG_STR_DECL(a);
 			DEBUG_STR_APPEND(a,hex);
 			DEBUG_STR_APPEND(a,"0x");
 			DEBUG_STR_APPEND(a,(int)write_loc[i]);
-			DEBUG_TRACE (DEBUG::MidiDiskstreamIO, DEBUG_STR(a).str());
+                        DEBUG_STR_APPEND(a,' ');
 		}
-		DEBUG_TRACE (DEBUG::MidiDiskstreamIO, "\n");
+                DEBUG_STR_APPEND(a,'\n');
+                DEBUG_TRACE (DEBUG::MidiDiskstreamIO, DEBUG_STR(a).str());
 #endif
 
 		if (success) {
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index fbd1f54..d25a70d 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -25,6 +25,7 @@
 
 #include "ardour/amp.h"
 #include "ardour/buffer_set.h"
+#include "ardour/debug.h"
 #include "ardour/delivery.h"
 #include "ardour/io_processor.h"
 #include "ardour/meter.h"
@@ -412,8 +413,12 @@ MidiTrack::write_out_of_band_data (BufferSet& bufs, sframes_t /*start*/, sframes
 {
 	// Append immediate events
 	MidiBuffer& buf (bufs.get_midi (0));
-	_immediate_events.read (buf, 0, 0, nframes - 1); // all stamps = 0
-
+        if (_immediate_events.read_space()) {
+                DEBUG_TRACE (DEBUG::MidiIO, string_compose ("%1 has %2 of immediate events to deliver\n", 
+                                                            name(), _immediate_events.read_space()));
+        }
+	_immediate_events.read (buf, 0, 1, nframes-1); // all stamps = 0
+        
 	// MIDI thru: send incoming data "through" output
 	if (_midi_thru && _session.transport_speed() != 0.0f && _input->n_ports().n_midi()) {
 		buf.merge_in_place (_input->midi(0)->get_midi_buffer(nframes));
@@ -474,6 +479,7 @@ MidiTrack::set_note_mode (NoteMode m)
 void
 MidiTrack::midi_panic()
 {
+        DEBUG_TRACE (DEBUG::MidiIO, string_compose ("%1 delivers panic data\n", name()));
 	for (uint8_t channel = 0; channel <= 0xF; channel++) {
 		uint8_t ev[3] = { MIDI_CMD_CONTROL | channel, MIDI_CTL_SUSTAIN, 0 };
 		write_immediate_event(3, ev);
diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc
index 6ae0c5d..5f29503 100644
--- a/libs/ardour/port.cc
+++ b/libs/ardour/port.cc
@@ -316,3 +316,4 @@ Port::physically_connected () const
 
         return false;
 }
+
diff --git a/libs/ardour/session_butler.cc b/libs/ardour/session_butler.cc
index 7cbbd19..c92c060 100644
--- a/libs/ardour/session_butler.cc
+++ b/libs/ardour/session_butler.cc
@@ -67,6 +67,36 @@ static inline uint32_t next_power_of_two (uint32_t n)
  ---------------------------------------------------------------------------*/
 
 void
+Session::adjust_playback_buffering ()
+{
+        request_stop (false, false);
+	SessionEvent *ev = new SessionEvent (SessionEvent::AdjustPlaybackBuffering, SessionEvent::Add, SessionEvent::Immediate, 0, 0, 0.0);
+	queue_event (ev);
+}
+
+void
+Session::adjust_capture_buffering ()
+{
+        request_stop (false, false);
+	SessionEvent *ev = new SessionEvent (SessionEvent::AdjustCaptureBuffering, SessionEvent::Add, SessionEvent::Immediate, 0, 0, 0.0);
+	queue_event (ev);
+}
+
+void
+Session::schedule_playback_buffering_adjustment ()
+{
+	add_post_transport_work (PostTransportAdjustPlaybackBuffering);
+	_butler->schedule_transport_work ();
+}
+
+void
+Session::schedule_capture_buffering_adjustment ()
+{
+	add_post_transport_work (PostTransportAdjustCaptureBuffering);
+	_butler->schedule_transport_work ();
+}
+
+void
 Session::schedule_curve_reallocation ()
 {
 	add_post_transport_work (PostTransportCurveRealloc);
diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc
index 9549227..79b1953 100644
--- a/libs/ardour/session_process.cc
+++ b/libs/ardour/session_process.cc
@@ -1091,6 +1091,14 @@ Session::process_event (SessionEvent* ev)
 		del = false; // other side of RT request needs to clean up
 		break;
 
+        case SessionEvent::AdjustPlaybackBuffering:
+                schedule_playback_buffering_adjustment ();
+                break;
+
+        case SessionEvent::AdjustCaptureBuffering:
+                schedule_capture_buffering_adjustment ();
+                break;
+
 	default:
 	  fatal << string_compose(_("Programming error: illegal event type in process_event (%1)"), ev->type) << endmsg;
 		/*NOTREACHED*/
diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc
index 898af1f..e6ff844 100644
--- a/libs/ardour/session_transport.cc
+++ b/libs/ardour/session_transport.cc
@@ -260,7 +260,28 @@ Session::butler_transport_work ()
 	ptw = post_transport_work();
 
 	DEBUG_TRACE (DEBUG::Transport, string_compose ("Butler transport work, todo = %1\n", enum_2_string (ptw)));
-		     
+
+        if (ptw & PostTransportAdjustPlaybackBuffering) {
+		for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+			boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+			if (tr) {
+				tr->adjust_playback_buffering ();
+                                /* and refill those buffers ... */
+                                tr->non_realtime_locate (_transport_frame);
+			}
+		}
+                
+        }
+
+        if (ptw & PostTransportAdjustCaptureBuffering) {
+		for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+			boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+			if (tr) {
+				tr->adjust_capture_buffering ();
+			}
+		}
+        }
+
 	if (ptw & PostTransportCurveRealloc) {
 		for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
 			(*i)->curve_reallocate();
diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc
index 870936a..ad4c765 100644
--- a/libs/ardour/track.cc
+++ b/libs/ardour/track.cc
@@ -665,3 +665,19 @@ Track::set_block_size (nframes_t n)
 	Route::set_block_size (n);
 	_diskstream->set_block_size (n);
 }
+
+void 
+Track::adjust_playback_buffering ()
+{
+        if (_diskstream) {
+                _diskstream->adjust_playback_buffering ();
+        }
+}
+
+void 
+Track::adjust_capture_buffering ()
+{
+        if (_diskstream) {
+                _diskstream->adjust_capture_buffering ();
+        }
+}
diff --git a/libs/midi++2/midi++/jack.h b/libs/midi++2/midi++/jack.h
index b720166..0433e4a 100644
--- a/libs/midi++2/midi++/jack.h
+++ b/libs/midi++2/midi++/jack.h
@@ -30,6 +30,7 @@
 
 #include <glibmm/thread.h>
 
+#include <jack/weakjack.h>
 #include <jack/jack.h>
 #include <jack/midiport.h>
 
