View Issue Details

IDProjectCategoryView StatusLast Update
0003210ardourbugspublic2010-07-20 15:41
Reporteroofus Assigned Tooofus  
PrioritynormalSeveritymajorReproducibilityalways
Status closedResolutionfixed 
PlatformDell D830 core2duo T9300 2.5GHzOSMandrivaOS Version2010
Target Version3.0-beta1 
Summary0003210: The summary overview becomes very difficult to use when you start changing track heights
DescriptionThe summary overview becomes very difficult to use when you start changing track heights. See attached screenshots.

As a track is made taller the others get shorter (in the overview) and more blank space is shown.

Maybe tracks should not be resized in the overview ie if there are 8 tracks they should take up an equal amount of height, from top to bottom, with no empty space at the bottom.

The horizontal layout of the overview seems to work fine.
TagsNo tags attached.

Activities

2010-05-30 18:05

 

Overview_1.png (84,287 bytes)   
Overview_1.png (84,287 bytes)   

2010-05-30 18:05

 

Overview_2.png (88,371 bytes)   
Overview_2.png (88,371 bytes)   

cth103

2010-06-05 10:43

administrator   ~0008159

There are a couple of issues:

1. track heights in the summary are limited to a maximum, so if there are only a few tracks there will be blank space at the bottom of the summary. I can't remember quite why we did this :)

2. track heights in the summary reflect heights in the editor; I'm not sure whether summary tracks should perhaps all be the same height.

lincoln

2010-06-05 11:00

reporter   ~0008160

For point 2. I would keep all heights in summary the same. There really is no use for them to reflect actual editor height.

paul

2010-06-07 14:04

administrator   ~0008187

for point 1: its because it looks incredibly ugly otherwise.

for point 2: i agree with lincoln that they should all be the same height in the summary view.

cth103

2010-06-07 19:16

administrator   ~0008190

For point 1: maybe there's a compromise whereby we scale track heights in some way similar to how they are in the editor; if the editor has, say, 2 tracks that are scaled to fill the entire window, the summary could reflect this. Otherwise there could be blank space in the summary to correspond to that in the editor.

cth103

2010-06-08 01:58

administrator   ~0008194

The snag with 2 (which I had forgotten) is that the summary's view box behaviour (both its display and moving it around) may be a little odd, as it will have to change size as it moves around.

oofus

2010-06-08 11:35

developer   ~0008201

I think in my original point (quite clumsily put) I was saying that, as has been noted about point 2, tracks in the overview shouldn't reflect the height of tracks in the editor, they should all just be the same height. I also think the solution is much simpler for point 1; the tracks should just fit to the height of the summary view, I don't think they need clamping to a max height, or showing any blank space at all. In fact I think it is the blank space that is causing the biggest problems. If the user drags it to be almost the size of the whole window, so what ! I don't think most will do that, so it will be fine.

cth103

2010-06-11 00:28

administrator   ~0008219

The attached patch removes the maximum height restriction for tracks in the summary, but makes the summary include any blank space that exists underneath tracks in the editor.

I think this makes the summary display more intuitive when there are only a few tracks.

I will work on the constant-track-height idea, but it has its complexities; for example if the summary viewbox is being dragged over a session with different track heights, the editor view will move at varying speeds, as a single pixel in the summary no longer corresponds to a constant amount of space in the editor.

2010-06-11 10:26

 

summary1.patch (65,802 bytes)   
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>
 
summary1.patch (65,802 bytes)   

cth103

2010-06-11 10:26

administrator   ~0008220

Updated patch to actually work!

oofus

2010-06-14 13:29

developer   ~0008235

I still say it is the blank space that is the problem. I have a session with 16 tracks and when I expand the overview (to a normal working/useful size) those tracks take up about the top 30% of it. 70% is blank space.

oofus

2010-06-14 13:35

developer   ~0008236

Actually on further investigation it becomes apparent that the overview only displays regions, there is no indication of the tracks. Maybe this is part of the problem. ie I create 16 tracks but only put a region on track 1. In the overview the only coloured block is that region on track 1, everything else is black. This possibly gives the impression of unused empty space. Maybe tracks themselves should be shown as lanes and the regions placed on those, the black space might not then look as unused.

2010-06-14 13:38

 

Track_overview.png (16,568 bytes)   
Track_overview.png (16,568 bytes)   

oofus

2010-06-14 13:39

developer   ~0008237

I've attached a screenshot of another DAWs overview for inspiration :)

paul

2010-06-14 13:41

administrator   ~0008238

methinks we've hit paydirt here ....

2010-06-14 13:41

 

Track_overview2.png (16,180 bytes)   
Track_overview2.png (16,180 bytes)   

cth103

2010-06-15 00:06

administrator   ~0008241

I've committed the patch above, and also made the summary plot tracks as well as regions.

oofus

2010-06-15 00:33

developer   ~0008242

That's made a big difference. Nice one.

As a side note, the overview doesn't seem to display midi regions.

cth103

2010-06-15 00:43

administrator   ~0008243

Strange... it does for me...

oofus

2010-06-15 10:48

developer   ~0008244

My fault sorry. What few midi regions I have are very small and the session length quite large. They were just too small to show up. In a different session with larger midi regions and and shorter session length, they show up fine.

cth103

2010-06-15 17:40

administrator   ~0008246

Tracks are now plotted at a constant height in the summary.

oofus

2010-06-15 20:34

developer   ~0008250

this is now getting much better.

One issue though. if you click and drag to the left or right of the view window it's supposed to scroll horizontally, but lock the vertical axis. What is happening is that when you drag the view window jumps a bit either up or down before then being locked vertically.

oofus

2010-06-15 22:08

developer   ~0008251

Question: Should the overview show hidden tracks and busses ?

cth103

2010-06-15 23:44

administrator   ~0008252

The jump up/down should hopefully be fixed now. I don't think the overview should show hidden tracks, and I've patched it accordingly ;)

lincoln

2010-06-15 23:56

reporter   ~0008254

Agreed, this is making allot more sense now.

oofus

2010-06-16 00:41

developer   ~0008255

The arrows at each end of the overview should repeat if you click and hold on them.

oofus

2010-06-16 00:51

developer   ~0008256

If you ctrl+click and drag on the left or right hand end of the view window in the overview, that window can be expanded or contracted horizontally. It would be good to be able to do the same vertically.

maybe all four edges of the view window should present the double headed arrow to indicate that that edge can be dragged to change its size. Then ctrl+click becomes unnecessary and resizing easier to discover.

cth103

2010-06-17 00:04

administrator   ~0008259

Dragging on the edges of the view box might be a bit tricky if the box is small. But then if it's small you can't do much with it anyway, really. Any thoughts there?

Auto-repeat on the arrows is implemented.

I'll have another go at the vertical zoom. I remember it being tricky for some reason!

oofus

2010-06-17 00:31

developer   ~0008260

Yeah I think ctrl + dragging would be equally tricky if the window was small so dragging the edges is my preferred method, and then vertical scrolling just falls into place !

Mouse over icons should be appropriate as well. ie when over the box a N,S,E,W 4 headed arrow to indicate it can be moved around and the appropriate double headed arrow over the box edges to indicate they can be dragged in or out.

cth103

2010-06-18 00:06

administrator   ~0008261

Dragging of summary box edges (and vertical zoom) is implemented in SVN.

oofus

2010-06-18 00:29

developer   ~0008262

Really good. Although tracks changing height when zooming vertically is a bit disconcerting !

The editor doesn't update until you stop dragging in the overview. Pretty sure it used to update in real time. Am I right ?

cth103

2010-06-18 01:04

administrator   ~0008266

Any ideas to make it less disconcerting...?

Yeah, the zoom used to be in real-time. I haven't (yet) found a way to make the vertical zoom behave nicely if its done like that. Do you think real-time operation is desirable?

oofus

2010-07-20 15:13

developer   ~0008504

The overview is now in a much better and usable state, so I consider this issue resolved. Any further issues will be bugs and need reporting separately.

oofus

2010-07-20 15:41

developer   ~0008505

Re-worked

Issue History

Date Modified Username Field Change
2010-05-30 18:05 oofus New Issue
2010-05-30 18:05 oofus File Added: Overview_1.png
2010-05-30 18:05 oofus File Added: Overview_2.png
2010-06-05 10:43 cth103 Note Added: 0008159
2010-06-05 10:44 cth103 Status new => acknowledged
2010-06-05 11:00 lincoln Note Added: 0008160
2010-06-07 14:04 paul Note Added: 0008187
2010-06-07 19:16 cth103 Note Added: 0008190
2010-06-08 01:59 cth103 Note Added: 0008194
2010-06-08 11:35 oofus Note Added: 0008201
2010-06-11 00:25 cth103 File Added: summary1.patch
2010-06-11 00:28 cth103 Note Added: 0008219
2010-06-11 10:26 cth103 File Deleted: summary1.patch
2010-06-11 10:26 cth103 File Added: summary1.patch
2010-06-11 10:26 cth103 Note Added: 0008220
2010-06-14 13:29 oofus Note Added: 0008235
2010-06-14 13:35 oofus Note Added: 0008236
2010-06-14 13:38 oofus File Added: Track_overview.png
2010-06-14 13:39 oofus Note Added: 0008237
2010-06-14 13:41 paul Note Added: 0008238
2010-06-14 13:41 oofus File Added: Track_overview2.png
2010-06-15 00:06 cth103 Note Added: 0008241
2010-06-15 00:33 oofus Note Added: 0008242
2010-06-15 00:43 cth103 Note Added: 0008243
2010-06-15 10:48 oofus Note Added: 0008244
2010-06-15 17:40 cth103 Note Added: 0008246
2010-06-15 20:34 oofus Note Added: 0008250
2010-06-15 22:08 oofus Note Added: 0008251
2010-06-15 23:44 cth103 Note Added: 0008252
2010-06-15 23:56 lincoln Note Added: 0008254
2010-06-16 00:41 oofus Note Added: 0008255
2010-06-16 00:51 oofus Note Added: 0008256
2010-06-16 23:27 cth103 cost => 0.00
2010-06-16 23:27 cth103 Target Version => 3.0-beta1
2010-06-17 00:04 cth103 Note Added: 0008259
2010-06-17 00:31 oofus Note Added: 0008260
2010-06-18 00:06 cth103 Note Added: 0008261
2010-06-18 00:29 oofus Note Added: 0008262
2010-06-18 01:04 cth103 Note Added: 0008266
2010-07-20 15:13 oofus Note Added: 0008504
2010-07-20 15:13 oofus Status acknowledged => resolved
2010-07-20 15:13 oofus Resolution open => fixed
2010-07-20 15:13 oofus Assigned To => oofus
2010-07-20 15:41 oofus Status resolved => feedback
2010-07-20 15:41 oofus Resolution fixed => reopened
2010-07-20 15:41 oofus Note Added: 0008505
2010-07-20 15:41 oofus Status feedback => closed
2010-07-20 15:41 oofus Resolution reopened => fixed