diff -aur ardour-2.8.11.orig/gtk2_ardour/gain_meter.cc ardour-2.8.11/gtk2_ardour/gain_meter.cc
--- ardour-2.8.11.orig/gtk2_ardour/gain_meter.cc	2010-04-20 19:28:37.000000000 +0200
+++ ardour-2.8.11/gtk2_ardour/gain_meter.cc	2011-07-18 22:36:49.000000000 +0200
@@ -89,11 +89,11 @@
 	if (horizontal) {
 		gain_slider = manage (new HSliderController (pix,
 							     &gain_adjustment,
-							     false));
+							     NULL));
 	} else {
 		gain_slider = manage (new VSliderController (pix,
 							     &gain_adjustment,
-							     false));
+							     NULL));
 	}
 
 	level_meter = new LevelMeter(_session);
@@ -168,6 +168,7 @@
 
 	level_meter->set_io (_io);
 	gain_slider->set_controllable (&_io->gain_control());
+	gain_slider->set_touch_controllable (&_io->touch_control());
 
 	boost::shared_ptr<Route> r;
 	
diff -aur ardour-2.8.11.orig/libs/ardour/ardour/io.h ardour-2.8.11/libs/ardour/ardour/io.h
--- ardour-2.8.11.orig/libs/ardour/ardour/io.h	2010-04-22 18:03:25.000000000 +0200
+++ ardour-2.8.11/libs/ardour/ardour/io.h	2011-07-18 22:36:49.000000000 +0200
@@ -196,6 +196,14 @@
 		return _gain_control;
 	}
 	
+	PBD::Controllable& touch_control() {
+		return _touch_control;
+	}
+
+	const PBD::Controllable& touch_control() const {
+		return _touch_control;
+	}
+	
 	/* Peak metering */
 
 	float peak_input_power (uint32_t n) { 
@@ -273,6 +281,8 @@
 	void start_gain_touch ();
 	void end_gain_touch ();
 
+	bool gain_touching() const { return _gain_automation_curve.touching(); }
+
 	void start_pan_touch (uint32_t which);
 	void end_pan_touch (uint32_t which);
 
@@ -329,7 +339,17 @@
 	    IO& io;
 	};
 
+	struct TouchControllable : public PBD::Controllable {
+	    TouchControllable (std::string name, IO& i) : Controllable (name), io (i) {}
+	 
+	    void set_value (float val);
+		  float get_value (void) const;
+   
+	    IO& io;
+	};
+
 	GainControllable _gain_control;
+	TouchControllable _touch_control;
 
 	nframes_t last_automation_snapshot;
 	static nframes_t _automation_interval;
diff -aur ardour-2.8.11.orig/libs/ardour/io.cc ardour-2.8.11/libs/ardour/io.cc
--- ardour-2.8.11.orig/libs/ardour/io.cc	2010-04-22 20:33:41.000000000 +0200
+++ ardour-2.8.11/libs/ardour/io.cc	2011-07-18 22:36:49.000000000 +0200
@@ -142,6 +142,7 @@
 	  _name (name),
 	  _default_type(default_type),
 	  _gain_control (X_("gaincontrol"), *this),
+	  _touch_control (X_("touchcontrol"), *this),
 	  _gain_automation_curve (0.0, 2.0, 1.0),
 	  _input_minimum (input_min),
 	  _input_maximum (input_max),
@@ -179,12 +180,14 @@
 	CycleStart.connect (mem_fun (*this, &IO::cycle_start));
 
 	_session.add_controllable (&_gain_control);
+	_session.add_controllable (&_touch_control);
 }
 
 IO::IO (Session& s, const XMLNode& node, DataType dt)
 	: _session (s),
 	  _default_type (dt),
 	  _gain_control (X_("gaincontrol"), *this),
+	  _touch_control (X_("touchcontrol"), *this),
 	  _gain_automation_curve (0, 0, 0) // all reset in set_state()
 {
 	_panner = 0;
@@ -214,6 +217,7 @@
 	CycleStart.connect (mem_fun (*this, &IO::cycle_start));
 
 	_session.add_controllable (&_gain_control);
+	_session.add_controllable (&_touch_control);
 }
 
 IO::~IO ()
@@ -1542,6 +1546,7 @@
 
 	node->add_child_nocopy (_panner->state (full_state));
 	node->add_child_nocopy (_gain_control.get_state ());
+	node->add_child_nocopy (_touch_control.get_state ());
 
 	snprintf (buf, sizeof(buf), "%2.12f", gain());
 	node->add_property ("gain", buf);
@@ -1632,8 +1637,13 @@
 		}
 
 		if ((*iter)->name() == X_("controllable")) {
-			if ((prop = (*iter)->property("name")) != 0 && prop->value() == "gaincontrol") {
-				_gain_control.set_state (**iter);
+			if ((prop = (*iter)->property("name")) != 0) {
+				if (prop->value() == "gaincontrol") {
+					_gain_control.set_state (**iter);
+				}
+				else if (prop->value() == "touchcontrol") {
+					_touch_control.set_state (**iter);
+				}
 			}
 		}
 	}
@@ -2484,6 +2494,21 @@
 }
 
 void
+IO::TouchControllable::set_value (float val)
+{
+	if (val)
+		io.start_gain_touch();
+	else
+		io.end_gain_touch();
+}
+
+float
+IO::TouchControllable::get_value (void) const
+{
+	return io.gain_touching() ? 1.0f : 0.0f;
+}
+
+void
 IO::reset_peak_meters ()
 {
 	uint32_t limit = max (_ninputs, _noutputs);
@@ -2669,6 +2694,7 @@
 void
 IO::start_gain_touch ()
 {
+	set_gain (_effective_gain, this);
 	_gain_automation_curve.start_touch (_session.transport_frame());
 }
 
diff -aur ardour-2.8.11.orig/libs/gtkmm2ext/binding_proxy.cc ardour-2.8.11/libs/gtkmm2ext/binding_proxy.cc
--- ardour-2.8.11.orig/libs/gtkmm2ext/binding_proxy.cc	2009-02-24 13:37:45.000000000 +0100
+++ ardour-2.8.11/libs/gtkmm2ext/binding_proxy.cc	2011-07-18 22:36:49.000000000 +0200
@@ -80,7 +80,7 @@
 bool
 BindingProxy::button_press_handler (GdkEventButton *ev)
 {
-	if ((ev->state & bind_statemask) && ev->button == bind_button) { 
+	if ((controllable != NULL) && ((ev->state & bind_statemask) == bind_statemask) && ev->button == bind_button) { 
 		if (Controllable::StartLearning (controllable)) {
 			string prompt = _("operate controller now");
 			if (prompter == 0) {
diff -aur ardour-2.8.11.orig/libs/gtkmm2ext/gtkmm2ext/slider_controller.h ardour-2.8.11/libs/gtkmm2ext/gtkmm2ext/slider_controller.h
--- ardour-2.8.11.orig/libs/gtkmm2ext/gtkmm2ext/slider_controller.h	2009-02-24 13:37:45.000000000 +0100
+++ ardour-2.8.11/libs/gtkmm2ext/gtkmm2ext/slider_controller.h	2011-07-18 22:36:49.000000000 +0200
@@ -52,8 +52,11 @@
 
 	void set_controllable (PBD::Controllable* c) { binding_proxy.set_controllable (c); }
 
+	void set_touch_controllable (PBD::Controllable* c) { binding_proxy_touch.set_controllable (c); }
+
   protected:
 	BindingProxy binding_proxy;
+	BindingProxy binding_proxy_touch;
 	Glib::RefPtr<Gdk::Pixbuf> slider;
 	Glib::RefPtr<Gdk::Pixbuf> rail;
 	Gtk::SpinButton     spin;
diff -aur ardour-2.8.11.orig/libs/gtkmm2ext/slider_controller.cc ardour-2.8.11/libs/gtkmm2ext/slider_controller.cc
--- ardour-2.8.11.orig/libs/gtkmm2ext/slider_controller.cc	2009-02-24 13:37:45.000000000 +0100
+++ ardour-2.8.11/libs/gtkmm2ext/slider_controller.cc	2011-07-18 22:36:49.000000000 +0200
@@ -35,12 +35,14 @@
 
 	: PixFader (image, *adj, orientation),
 	  binding_proxy (c),
+	  binding_proxy_touch (NULL),
 	  spin (*adj, 0, 2)
 {			  
 	spin.set_name ("SliderControllerValue");
 	spin.set_size_request (70,-1); // should be based on font size somehow
 	spin.set_numeric (true);
 	spin.set_snap_to_ticks (false);
+	binding_proxy_touch.set_bind_button_state (2, Gdk::SHIFT_MASK | Gdk::CONTROL_MASK);
 }
 
 void
@@ -52,6 +54,9 @@
 bool 
 SliderController::on_button_press_event (GdkEventButton *ev) 
 {
+	if (binding_proxy_touch.button_press_handler (ev)) {
+		return true;
+	}
 	if (binding_proxy.button_press_handler (ev)) {
 		return true;
 	}
diff -aur ardour-2.8.11.orig/libs/surfaces/generic_midi/midicontrollable.cc ardour-2.8.11/libs/surfaces/generic_midi/midicontrollable.cc
--- ardour-2.8.11.orig/libs/surfaces/generic_midi/midicontrollable.cc	2009-02-24 13:38:19.000000000 +0100
+++ ardour-2.8.11/libs/surfaces/generic_midi/midicontrollable.cc	2011-07-18 22:36:49.000000000 +0200
@@ -141,7 +141,7 @@
 		}
 	}
 
-	last_value = (MIDI::byte) (controllable.get_value() * 127.0); // to prevent feedback fights
+	last_value = (MIDI::byte) (controllable.get_value() * 127.0 + 0.5); // to prevent feedback fights
 }
 
 void
@@ -158,7 +158,7 @@
 			}
 		}
 
-		last_value = (MIDI::byte) (controllable.get_value() * 127.0); // to prevent feedback fights
+		last_value = (MIDI::byte) (controllable.get_value() * 127.0 + 0.5); // to prevent feedback fights
 	}
 }
 
@@ -169,7 +169,7 @@
 
 	if (!bistate) {
 		controllable.set_value (msg/127.0);
-		last_value = (MIDI::byte) (controllable.get_value() * 127.0); // to prevent feedback fights
+		last_value = (MIDI::byte) (controllable.get_value() * 127.0 + 0.5); // to prevent feedback fights
 	} 
 }
 
@@ -181,7 +181,7 @@
 	/* XXX gack - get rid of assumption about typeof pitchbend_t */
 
 	controllable.set_value ((pb/(float) SHRT_MAX));
-	last_value = (MIDI::byte) (controllable.get_value() * 127.0); // to prevent feedback fights
+	last_value = (MIDI::byte) (controllable.get_value() * 127.0 + 0.5); // to prevent feedback fights
 }			
 
 void
@@ -297,7 +297,7 @@
 
 	msg[0] = (control_type & 0xF0) | (control_channel & 0xF); 
 	msg[1] = control_additional;
-	msg[2] = (byte) (controllable.get_value() * 127.0f);
+	msg[2] = (byte) (controllable.get_value() * 127.0f + 0.5f);
 
 	_port.write (msg, 3);
 }
@@ -307,7 +307,7 @@
 {
 	if (control_type != none && feedback && bufsize > 2) {
 
-		MIDI::byte gm = (MIDI::byte) (controllable.get_value() * 127.0);
+		MIDI::byte gm = (MIDI::byte) (controllable.get_value() * 127.0 + 0.5);
 		
 		if (gm != last_value) {
 			*buf++ = (0xF0 & control_type) | (0xF & control_channel);
