diff -duPNr qtractor.0/Makefile.in qtractor.1/Makefile.in
--- qtractor.0/Makefile.in	2009-02-08 15:12:58.000000000 +0000
+++ qtractor.1/Makefile.in	2009-05-07 19:08:52.000000000 +0100
@@ -39,6 +39,7 @@
 	src/qtractorMidiBuffer.h \
 	src/qtractorMidiClip.h \
 	src/qtractorMidiConnect.h \
+	src/qtractorMidiController.h \
 	src/qtractorMidiCursor.h \
 	src/qtractorMidiEditor.h \
 	src/qtractorMidiEditCommand.h \
@@ -133,6 +134,7 @@
 	src/qtractorMidiBuffer.cpp \
 	src/qtractorMidiClip.cpp \
 	src/qtractorMidiConnect.cpp \
+	src/qtractorMidiController.cpp \
 	src/qtractorMidiCursor.cpp \
 	src/qtractorMidiEditor.cpp \
 	src/qtractorMidiEditCommand.cpp \
diff -duPNr qtractor.0/qtractor.pro.in qtractor.1/qtractor.pro.in
--- qtractor.0/qtractor.pro.in	2009-02-08 15:12:58.000000000 +0000
+++ qtractor.1/qtractor.pro.in	2009-05-07 19:08:21.000000000 +0100
@@ -35,6 +35,7 @@
            src/qtractorMidiBuffer.h \
            src/qtractorMidiClip.h \
            src/qtractorMidiConnect.h \
+           src/qtractorMidiController.h \
            src/qtractorMidiCursor.h \
            src/qtractorMidiEditor.h \
            src/qtractorMidiEditCommand.h \
@@ -130,6 +131,7 @@
            src/qtractorMidiBuffer.cpp \
            src/qtractorMidiClip.cpp \
            src/qtractorMidiConnect.cpp \
+           src/qtractorMidiController.cpp \
            src/qtractorMidiCursor.cpp \
            src/qtractorMidiEditor.cpp \
            src/qtractorMidiEditCommand.cpp \
diff -duPNr qtractor.0/src/qtractorMainForm.cpp qtractor.1/src/qtractorMainForm.cpp
--- qtractor.0/src/qtractorMainForm.cpp	2009-04-22 11:00:30.000000000 +0100
+++ qtractor.1/src/qtractorMainForm.cpp	2009-05-07 19:07:33.000000000 +0100
@@ -71,6 +71,8 @@
 
 #include "qtractorTrackCommand.h"
 
+#include "qtractorMidiController.h"
+
 #ifdef CONFIG_VST
 #include "qtractorVstPlugin.h"
 #endif
@@ -244,6 +246,9 @@
 		pMidiEngine->setNotifySppType(QTRACTOR_SPP_EVENT);
 	}
 
+	// add the midi controller map
+	m_pMidiController = new qtractorMidiController();
+
 #ifdef HAVE_SIGNAL_H
 	// Set to ignore any fatal "Broken pipe" signals.
 	::signal(SIGPIPE, SIG_IGN);
@@ -774,7 +779,11 @@
 	// Custom tempo cursor.
 	if (m_pTempoCursor)
 		delete m_pTempoCursor;
-	
+
+	// remove midi controller
+	if (m_pMidiController)
+		delete m_pMidiController;
+
 	// Pseudo-singleton reference shut-down.
 	g_pMainForm = NULL;
 }
@@ -1277,6 +1286,10 @@
 		.arg(pCtlEvent->controller())
 		.arg(pCtlEvent->value());
 
+	// TODO check if controller is used as midiController
+	if (m_pMidiController->processMidiControl(pCtlEvent))
+		return;
+
 	// FIXME: JCooper faders (as from US-224)...
 	if (pCtlEvent->channel() == 15) {
 		// Event translation...
diff -duPNr qtractor.0/src/qtractorMainForm.h qtractor.1/src/qtractorMainForm.h
--- qtractor.0/src/qtractorMainForm.h	2009-04-16 22:06:22.000000000 +0100
+++ qtractor.1/src/qtractorMainForm.h	2009-05-07 19:07:33.000000000 +0100
@@ -39,6 +39,7 @@
 class qtractorMixer;
 class qtractorMmcEvent;
 class qtractorMidiControlEvent;
+class qtractorMidiController;
 class qtractorMidiSppEvent;
 class qtractorTimeSpinBox;
 class qtractorTempoSpinBox;
@@ -330,6 +331,8 @@
 	int m_iMidiRefreshTimer;
 	int m_iPlayerTimer;
 
+	qtractorMidiController* m_pMidiController;
+
 	// Status bar item indexes
 	enum {
 		StatusName    = 0,   // Active session track caption.
diff -duPNr qtractor.0/src/qtractorMidiController.cpp qtractor.1/src/qtractorMidiController.cpp
--- qtractor.0/src/qtractorMidiController.cpp	1970-01-01 01:00:00.000000000 +0100
+++ qtractor.1/src/qtractorMidiController.cpp	2009-05-07 19:21:18.000000000 +0100
@@ -0,0 +1,574 @@
+// qtractorMidiController.cpp
+//
+/****************************************************************************
+   Copyright (C) 2005-2009, rncbc aka Rui Nuno Capela. All rights reserved.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*****************************************************************************/
+
+#include "qtractorMidiController.h"
+
+#include "qtractorSession.h"
+#include "qtractorMidiEngine.h"
+#include "qtractorMainForm.h"
+#include "qtractorMixer.h"
+#include "qtractorMeter.h"
+#include "qtractorTrackList.h"
+#include "qtractorTracks.h"
+#include "qtractorTrackCommand.h"
+#include "qtractorAudioMeter.h"
+
+#include <math.h>
+
+#include <QVector>
+
+// Meter level limits (in dB).
+#define QTRACTOR_AUDIO_MAXDB			+6.0f
+#define QTRACTOR_AUDIO_MINDB			-70.0f
+
+//----------------------------------------------------------------------------
+// IEC standard dB scaling -- as borrowed from meterbridge (c) Steve Harris
+
+static inline float IEC_Scale ( float dB )
+{
+	float fScale = 1.0f;
+
+	if (dB < -70.0f)
+		fScale = 0.0f;
+	else if (dB < -60.0f)
+		fScale = (dB + 70.0f) * 0.0025f;
+	else if (dB < -50.0f)
+		fScale = (dB + 60.0f) * 0.005f + 0.025f;
+	else if (dB < -40.0)
+		fScale = (dB + 50.0f) * 0.0075f + 0.075f;
+	else if (dB < -30.0f)
+		fScale = (dB + 40.0f) * 0.015f + 0.15f;
+	else if (dB < -20.0f)
+		fScale = (dB + 30.0f) * 0.02f + 0.3f;
+	else if (dB < -0.001f || dB > 0.001f)  /* if (dB < 0.0f) */
+		fScale = (dB + 20.0f) * 0.025f + 0.5f;
+
+	return fScale;
+}
+
+static inline float IEC_dB ( float fScale )
+{
+	float dB = 0.0f;
+
+	if (fScale < 0.025f)	    // IEC_Scale(-60.0f)
+		dB = (fScale / 0.0025f) - 70.0f;
+	else if (fScale < 0.075f)	// IEC_Scale(-50.0f)
+		dB = (fScale - 0.025f) / 0.005f - 60.0f;
+	else if (fScale < 0.15f)	// IEC_Scale(-40.0f)
+		dB = (fScale - 0.075f) / 0.0075f - 50.0f;
+	else if (fScale < 0.3f)		// IEC_Scale(-30.0f)
+		dB = (fScale - 0.15f) / 0.015f - 40.0f;
+	else if (fScale < 0.5f)		// IEC_Scale(-20.0f)
+		dB = (fScale - 0.3f) / 0.02f - 30.0f;
+	else /* if (fScale < 1.0f)	// IED_Scale(0.0f)) */
+		dB = (fScale - 0.5f) / 0.025f - 20.0f;
+
+	return (dB > -0.001f && dB < 0.001f ? 0.0f : dB);
+}
+
+// Possible  20 * log10(x) optimization
+// (borrowed from musicdsp.org)
+static inline float log10f2 ( float x )
+{
+#ifdef CONFIG_FLOAT32
+#	define M_LOG10F20 6.0205999132796239042f // (= 20.0f * M_LN2 / M_LN10)
+	int i = *(int *) &x;
+	return M_LOG10F20 * ((((i & 0x7f800000) >> 23) - 0x7f)
+		+ (i & 0x007fffff) / (float) 0x800000);
+#else
+	return 20.0f * ::log10f(x);
+#endif
+}
+
+
+//----------------------------------------------------------------------
+// class qtractorMidiControllerMapKey
+//
+
+class qtractorMidiControllerMapKey
+{
+public:
+
+	// Constructor.
+	qtractorMidiControllerMapKey()
+	{
+		m_channel = 0xffff;
+		m_controller = 0;
+	}
+
+	qtractorMidiControllerMapKey(unsigned short int channel,
+		unsigned short int controller)
+	{
+		m_channel = channel;
+		m_controller = controller;
+	}
+
+	// Accessors
+	void setChannel(unsigned short channel) {m_channel = channel;}
+	unsigned short channel() const {return m_channel;}
+	void setController (unsigned short controller) {m_controller = controller;}
+	unsigned short controller()  const {return m_controller;}
+
+	bool operator< (const qtractorMidiControllerMapKey& b) const
+	{
+		if (this->m_channel < b.m_channel)
+			return true;
+		if (this->m_controller < b.m_controller)
+			return true;
+
+		return false;
+	}
+
+	// Destructor.
+	~qtractorMidiControllerMapKey() {}
+
+private:
+
+	//unsigned int input;
+	unsigned short int m_channel;
+	unsigned short int m_controller;
+};
+
+
+//----------------------------------------------------------------------
+// class qtractorMidiControllerMapEntry
+//
+
+class qtractorMidiControllerMapVal
+{
+public:
+
+	// Constructor.
+	qtractorMidiControllerMapVal()
+	{
+		m_iParameter = 0;
+		m_iValue = 0;
+		m_command = qtractorMidiController::NONE;
+	}
+
+	// Destructor.
+	~qtractorMidiControllerMapVal() {}
+
+	// send this value to midi bus
+	void send(int iController)
+	{
+		// get the MIDI engine
+		qtractorSession* pSession = qtractorSession::getInstance();
+		if (pSession == NULL)
+			 return;
+
+		qtractorMidiEngine *pEngine = pSession->midiEngine();
+		if (pEngine == NULL)
+			return;
+
+		pEngine->controlBus_out()->sendController(m_iParameter,
+				iController, m_iValue);
+	}
+
+	// Accessors
+	void setCommand(qtractorMidiController::Command command) {m_command = command;}
+	qtractorMidiController::Command command() const {return m_command;}
+	void setParameter (int iParameter) {m_iParameter = iParameter;}
+	int parameter() const {return m_iParameter;}
+	void setValue (int iValue) {m_iValue = iValue;}
+	int value() const {return m_iValue;}
+
+private:
+
+	qtractorMidiController::Command m_command;
+	int m_iParameter;
+	int m_iValue;
+};
+
+
+
+//----------------------------------------------------------------------
+// class qtractorMidiController
+//
+
+// Kind of singleton reference.
+qtractorMidiController* qtractorMidiController::g_pMidiController = NULL;
+
+// Constructor.
+qtractorMidiController::qtractorMidiController (void)
+{
+	// Pseudo-singleton reference setup.
+	g_pMidiController = this;
+
+	// generate a dummy controller map
+	qtractorMidiControllerMapKey key;
+	qtractorMidiControllerMapVal val;
+
+	// level controllers
+	for (unsigned int i=0; i < 8; i++) {
+		key.setChannel(i);
+		key.setController(7);
+		val.setCommand(qtractorMidiController::TRACKGAIN);
+		val.setParameter(i);
+		m_midiControllerMap[key] = val;
+	}
+
+	// pan controllers
+	for (unsigned int i=0; i < 8; i++) {
+		key.setChannel(i);
+		key.setController(10);
+		val.setCommand(qtractorMidiController::TRACKPAN);
+		val.setParameter(i);
+		m_midiControllerMap[key] = val;
+	}
+
+	// mutes
+	for (unsigned int i=0; i < 8; i++) {
+		key.setChannel(i);
+		key.setController(20);
+		val.setCommand(qtractorMidiController::TRACKMUTE);
+		val.setParameter(i);
+		m_midiControllerMap[key] = val;
+	}
+}
+
+
+// Destructor.
+qtractorMidiController::~qtractorMidiController (void)
+{
+	// Pseudo-singleton reference shut-down.
+	g_pMidiController = NULL;
+}
+
+
+// kind of singleton reference.
+qtractorMidiController *qtractorMidiController::getInstance (void)
+{
+	return g_pMidiController;
+}
+
+
+// resend all the controllers (as output bus changed, or session initialized)
+void qtractorMidiController::resendControllersOut (void)
+{
+	qtractorMainForm *pMainForm = qtractorMainForm::getInstance();
+	if (pMainForm == NULL) {
+		return;
+	}
+
+	pMainForm->appendMessages(
+		QObject::tr("resendControllersOut..."));
+
+	// walk through midi controller map
+	qtractorMidiControllerMap::Iterator it;
+	for (it = m_midiControllerMap.begin(); it != m_midiControllerMap.end(); ++it ) {
+		// now send the message to control bus
+		it.value().send(it.key().controller());
+
+		/*
+		pEngine->controlBus_out()->sendController(
+				it.value().parameter(),
+				it.key().controller(),
+				it.value().data());
+				*/
+	}
+}
+
+
+// Process incoming controller event
+bool qtractorMidiController::processMidiControl (
+	qtractorMidiControlEvent *pEvent )
+{
+	// check if controller map includes this event
+	qtractorMidiControllerMapKey key(pEvent->channel(), pEvent->controller());
+	qtractorMidiControllerMap::Iterator it;
+	it = m_midiControllerMap.find(key);
+	// TODO check if there's a controller with all channels activated
+	if (it == m_midiControllerMap.end()) {
+		// we did not find anything, return with false for further handling
+		return false;
+	}
+
+	// depending from command, handle it
+	// TODO (should be done with real command
+	// classes)
+
+	// if value did not change, we do nothing
+	if (it.value().value() == pEvent->value())
+		return true;
+
+	// set the controller data in map
+	it.value().setValue(pEvent->value());
+
+	// get instance of main form for debugging
+	qtractorMainForm *pMainForm = qtractorMainForm::getInstance();
+	if (pMainForm == NULL)
+		return true;
+
+	switch (it.value().command()) {
+
+	case TRACKGAIN:
+	{
+		int iTrack = it.value().parameter();
+		float fGain = float(pEvent->value()) / 127.0f;
+
+		// Find the track by number...
+		qtractorSession * pSession = qtractorSession::getInstance();
+		if (pSession == NULL)
+			return true;
+
+		if (pSession->tracks().count() <= iTrack)
+			return true;
+
+		qtractorTrack *pTrack = pSession->tracks().at(iTrack);
+		if (pTrack == NULL)
+			return true;
+
+		if (pTrack->trackType() == qtractorTrack::Audio) {
+			fGain = float(pEvent->value()) / 127.0f;
+			fGain = (fGain * (QTRACTOR_AUDIO_MAXDB - (QTRACTOR_AUDIO_MINDB))) + QTRACTOR_AUDIO_MINDB;
+			fGain = IEC_Scale(fGain);
+			fGain = powf(10.0f, IEC_dB(fGain) / 20.0f);
+			pMainForm->appendMessages(
+				QObject::tr("processMidiControl: (gain %1)").arg(fGain));
+		} else {
+			fGain = float(pEvent->value()) / 127.0f;
+		}
+
+		// set gain in midi track
+		pTrack->setGain(fGain);
+		if (pTrack->trackType() == qtractorTrack::Midi) {
+			// Now we gotta make sure of proper MIDI bus...
+			qtractorMidiBus *pMidiBus
+				= static_cast<qtractorMidiBus *> (pTrack->outputBus());
+			if (pMidiBus)
+				pMidiBus->setVolume(pTrack, fGain);
+		}
+
+		// update the mixer
+		qtractorMixer *pMixer = pMainForm->mixer();
+		if (pMixer) {
+			qtractorMixerStrip *pStrip
+				= pMixer->trackRack()->findStrip(pTrack->monitor());
+			if (pStrip && pStrip->meter()) {
+				//float fGain = pStrip->meter()->gainFromValue(fGain);
+				//pTrack->setGain(fGain);
+				pStrip->meter()->updateGain();
+			}
+		}
+
+		break;
+	}
+
+	case TRACKPAN:
+	{
+		int iTrack = it.value().parameter();
+		float fPan  = float(pEvent->value()) / 63.5f - 1.0;
+
+		// Find the track by number...
+		qtractorSession * pSession = qtractorSession::getInstance();
+		if (pSession == NULL)
+			return true;
+
+		if (pSession->tracks().count() <= iTrack)
+			return true;
+
+		qtractorTrack *pTrack = pSession->tracks().at(iTrack);
+		if (pTrack == NULL)
+			return true;
+
+		// set gain in track
+		pTrack->setPanning(fPan);
+		if (pTrack->trackType() == qtractorTrack::Midi) {
+			qtractorMidiBus *pMidiBus
+				= static_cast<qtractorMidiBus *> (pTrack->outputBus());
+			if (pMidiBus)
+				pMidiBus->setPanning(pTrack, fPan);
+		}
+
+		// update the mixer
+		qtractorMixer *pMixer = pMainForm->mixer();
+		if (pMixer) {
+			qtractorMixerStrip *pStrip
+				= pMixer->trackRack()->findStrip(pTrack->monitor());
+			if (pStrip && pStrip->meter())
+				pStrip->meter()->updatePanning();
+		}
+
+		break;
+	}
+
+	case TRACKMUTE:
+	{
+		int iTrack = it.value().parameter();
+		bool bMute  = bool(pEvent->value());
+
+		// Find the track by number...
+		qtractorSession *pSession = qtractorSession::getInstance();
+		if (pSession == NULL)
+			 return true;
+
+		if (pSession->tracks().count() <= iTrack)
+			return true;
+
+		qtractorTrack *pTrack = pSession->tracks().at(iTrack);
+		if (pTrack == NULL)
+			return true;
+
+		// set mute in track
+		pTrack->setMute(bMute);
+
+		// Track-list and mixer update...
+		qtractorMidiEngine *pMidiEngine = pSession->midiEngine();
+		qtractorTrackList  *pTrackList  = pMainForm->tracks()->trackList();
+
+		// Send MMC MASKED_WRITE command...
+		pMidiEngine->sendMmcMaskedWrite(qtractorMmcEvent::TRACK_MUTE,
+				iTrack, bMute);
+
+		// Update track list item...
+		if (pTrackList)
+			pTrackList->updateTrack(pTrack);
+
+		// Toggle/update all other?
+		qtractorMixerRack *pTrackRack = pMainForm->mixer()->trackRack();
+		//if (m_tracks.isEmpty()) {
+			// Update one track mixer strip...
+			qtractorMixerStrip *pStrip
+				= pTrackRack->findStrip(pTrack->monitor());
+			if (pStrip)
+				pStrip->updateTrackButtons();
+			// Done with single mode.
+		//} else {
+			// Exclusive mode.
+		/*
+			QListIterator<TrackItem *> iter(m_tracks);
+			while (iter.hasNext()) {
+				TrackItem *pTrackItem = iter.next();
+				pTrack = pTrackItem->track;
+				bOn = false;
+				if (m_toolType == qtractorTrack::Mute) {
+					bOn = pTrack->isMute();
+					pTrack->setMute(pTrackItem->on);
+				}
+				else
+				if (m_toolType == qtractorTrack::Solo) {
+					bOn = pTrack->isSolo();
+					pTrack->setSolo(pTrackItem->on);
+				}
+				// Send MMC MASKED_WRITE command...
+				pMidiEngine->sendMmcMaskedWrite(scmd,
+					pTrackList->trackRow(pTrack), pTrackItem->on);
+				// Update track list item...
+				pTrackList->updateTrack(pTrack);
+				// Swap for undo...
+				pTrackItem->on = bOn;
+			}
+			// Update all track mixer strips...
+			pTrackRack->updateTrackButtons();
+			// Done with exclusive mode.
+			 * */
+		//}
+		break;
+	}
+
+	default:
+		pMainForm->appendMessages(
+			QObject::tr("processMidiControl: unknown command"));
+		break;
+	}
+
+	return true;
+}
+
+
+// Process incoming command
+void qtractorMidiController::processCommand (
+	Command command, int iPar, float fValue )
+{
+	qtractorMainForm *pMainForm = qtractorMainForm::getInstance();
+	if (pMainForm == NULL)
+		return;
+
+	// debug output
+	pMainForm->appendMessages(
+		QObject::tr("processCommand: (value %1 par %2)").arg(fValue).arg(iPar));
+
+	// calculate the midi controller value
+	int iValue = 0;
+	switch (command) {
+	case TRACKGAIN:
+		iValue = int(fValue * 127.0);
+		/* TODO if it is a audio bus, we have to calc the right gain value */
+		//fValue =  (fValue > 0.0f ? log10f2(fValue) : QTRACTOR_AUDIO_METER_MINDB);
+		setMidiController(command, iPar, iValue);
+		break;
+	case TRACKPAN:
+		iValue = int((fValue + 1.0) * 63.5);
+		setMidiController(command, iPar, iValue);
+		break;
+	default:
+		break;
+	}
+
+}
+
+
+void qtractorMidiController::processCommand (
+	Command command, int iPar, bool bValue )
+{
+	qtractorMainForm *pMainForm = qtractorMainForm::getInstance();
+	if (pMainForm == NULL)
+		return;
+
+	// debug output
+	pMainForm->appendMessages(
+		QObject::tr("processCommand: (value %1 par %2)").arg(bValue).arg(iPar));
+
+	// calculate the midi controller value
+	int iValue = 0;
+	switch (command) {
+	case TRACKMUTE:
+		iValue = (bValue ? 127 : 0);
+		setMidiController(command, iPar, iValue);
+		break;
+	default:
+		break;
+	}
+}
+
+
+// Further processing of outgoing midi controller messages
+void qtractorMidiController::setMidiController(
+	Command command, int iPar, int iValue)
+{
+	// search for the command and parameter in controller map
+	qtractorMidiControllerMap::Iterator it;
+	for (it = m_midiControllerMap.begin(); it != m_midiControllerMap.end(); ++it ) {
+		if (it.value().command() == command && it.value().parameter() == iPar) {
+			// check if value changed
+			if (it.value().value() != iValue) {
+				// set the value of the controller
+				it.value().setValue(iValue);
+				// now send the message to control bus
+				it.value().send(it.key().controller());
+			}
+		}
+	}
+}
+
+
+// end of qtractorMidiController.cpp
diff -duPNr qtractor.0/src/qtractorMidiController.h qtractor.1/src/qtractorMidiController.h
--- qtractor.0/src/qtractorMidiController.h	1970-01-01 01:00:00.000000000 +0100
+++ qtractor.1/src/qtractorMidiController.h	2009-05-07 19:13:01.000000000 +0100
@@ -0,0 +1,89 @@
+// qtractorMidiController.h
+//
+/****************************************************************************
+   Copyright (C) 2005-2009, rncbc aka Rui Nuno Capela. All rights reserved.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*****************************************************************************/
+
+#ifndef __qtractorMidiController_h
+#define __qtractorMidiController_h
+
+//#include <QString>
+#include <QMap>
+
+// Forward declarations
+class qtractorMidiControlEvent;
+class qtractorMidiControllerMapKey;
+class qtractorMidiControllerMapVal;
+
+
+//----------------------------------------------------------------------
+// class qtractorMidiController
+//
+
+typedef QMap<qtractorMidiControllerMapKey, qtractorMidiControllerMapVal>
+	qtractorMidiControllerMap;
+
+class qtractorMidiController
+{
+public:
+
+	// Controller types.
+	enum Command {
+		TRACKGAIN     = 0,
+		TRACKPAN	  = 1,
+		TRACKMUTE	  = 2,
+		NONE		  = 0xffff
+	};
+
+	// Constructor.
+	qtractorMidiController();
+
+	// Destructor.
+	~qtractorMidiController();
+
+	static qtractorMidiController *getInstance();
+
+	// Re-send all controllers
+	void resendControllersOut();
+
+	// Process incoming controller messages
+	bool processMidiControl(qtractorMidiControlEvent* pEvent);
+
+	// Process incoming command
+	void processCommand(Command command, int iPar, float fValue);
+	void processCommand(Command command, int iPar, bool bValue);
+
+protected:
+
+	// Set data of a controller
+	void setMidiController(Command command, int iPar, int iValue);
+
+	// Helper for sending controller messages
+	//void processCommandEx(Command command, int iPar, int iValue);
+
+private:
+
+	qtractorMidiControllerMap m_midiControllerMap;
+
+	static qtractorMidiController *g_pMidiController;
+};
+
+
+#endif  // __qtractorMidiController_h
+
+// end of qtractorMidiController.h
diff -duPNr qtractor.0/src/qtractorMidiEngine.cpp qtractor.1/src/qtractorMidiEngine.cpp
--- qtractor.0/src/qtractorMidiEngine.cpp	2009-04-21 15:39:22.000000000 +0100
+++ qtractor.1/src/qtractorMidiEngine.cpp	2009-05-07 19:07:33.000000000 +0100
@@ -23,6 +23,7 @@
 #include "qtractorMidiEngine.h"
 #include "qtractorMidiMonitor.h"
 #include "qtractorMidiEvent.h"
+#include "qtractorMainForm.h"	// FIXME remove this after debugging
 
 #include "qtractorSessionCursor.h"
 #include "qtractorSessionDocument.h"
@@ -31,6 +32,7 @@
 #include "qtractorMidiSequence.h"
 #include "qtractorMidiClip.h"
 #include "qtractorMidiBuffer.h"
+#include "qtractorMidiController.h"
 
 #include "qtractorPlugin.h"
 
@@ -2316,8 +2318,17 @@
 
 	// Control bus outputs...
 	if (m_bControlBus && m_pOControlBus) {
-		iUpdate += m_pOControlBus->updateConnects(
+		iUpdate = m_pOControlBus->updateConnects(
 				qtractorBus::Output, m_pOControlBus->outputs(), true);
+
+		/* if control bus changed, re-check midi controllers */
+		/* FIXME check if control bus out really changed... */
+		qtractorMidiController *pMidiController
+			= qtractorMidiController::getInstance();
+
+		if (pMidiController) {
+			pMidiController->resendControllersOut();
+		}
 	}
 
 	// Metronome bus outputs...
@@ -2639,6 +2650,13 @@
 	setControllerEx(pTrack->midiChannel(), iController, iValue, pTrack);
 }
 
+// Direct MIDI controller helper.
+void qtractorMidiBus::sendController (unsigned short iChannel, int iController,
+	int iValue ) const
+{
+	setControllerEx(iChannel, iController, iValue, NULL);
+}
+
 
 // Direct MIDI controller common helper.
 void qtractorMidiBus::setControllerEx ( unsigned short iChannel,
diff -duPNr qtractor.0/src/qtractorMidiEngine.h qtractor.1/src/qtractorMidiEngine.h
--- qtractor.0/src/qtractorMidiEngine.h	2009-02-25 19:58:56.000000000 +0000
+++ qtractor.1/src/qtractorMidiEngine.h	2009-05-07 19:07:33.000000000 +0100
@@ -308,6 +308,9 @@
 	void setController(qtractorTrack *pTrack,
 		int iController, int iValue = 0) const;
 
+	void sendController (unsigned short iChannel, int iController,
+		int iValue ) const;
+
 	// Direct MIDI note helper.
 	void sendNote(qtractorTrack *pTrack,
 		int iNote, int iVelocity = 0) const;
diff -duPNr qtractor.0/src/qtractorTrackCommand.cpp qtractor.1/src/qtractorTrackCommand.cpp
--- qtractor.0/src/qtractorTrackCommand.cpp	2008-12-07 15:59:21.000000000 +0000
+++ qtractor.1/src/qtractorTrackCommand.cpp	2009-05-07 19:07:33.000000000 +0100
@@ -32,6 +32,7 @@
 #include "qtractorMidiEngine.h"
 #include "qtractorMixer.h"
 #include "qtractorMeter.h"
+#include "qtractorMidiController.h"
 
 
 //----------------------------------------------------------------------
@@ -555,6 +556,21 @@
 	// Update track list item...
 	pTrackList->updateTrack(pTrack);
 
+	// set mute in MIDI controllers
+	if (m_toolType == qtractorTrack::Mute) {
+		int iTrack = -1;
+		qtractorSession *pSession = qtractorSession::getInstance();
+		if (pSession) {
+			iTrack = pSession->tracks().find(pTrack);
+		}
+		qtractorMidiController *pMidiController
+			= qtractorMidiController::getInstance();
+		if (pMidiController) {
+			pMidiController->processCommand(
+				qtractorMidiController::TRACKMUTE, iTrack, m_bOn);
+		}
+	}
+
 	// Reset for undo.
 	m_bOn = bOn;
 
@@ -759,6 +775,19 @@
 			pMidiBus->setVolume(pTrack, m_fGain);
 	}
 
+	// set gain in MIDI controllers
+	int iTrack = -1;
+	qtractorSession *pSession = qtractorSession::getInstance();
+	if (pSession) {
+		iTrack = pSession->tracks().find(pTrack);
+	}
+	qtractorMidiController *pMidiController
+		= qtractorMidiController::getInstance();
+	if (pMidiController) {
+		pMidiController->processCommand(
+			qtractorMidiController::TRACKGAIN, iTrack, m_fGain);
+	}
+
 	// Set undo value...
 	m_bPrevGain = false;
 	m_fPrevGain = m_fGain;
@@ -843,7 +872,20 @@
 		if (pMidiBus)
 			pMidiBus->setPanning(pTrack, m_fPanning);
 	}
-	
+
+	// set gain in MIDI controllers
+	int iTrack = -1;
+	qtractorSession *pSession = qtractorSession::getInstance();
+	if (pSession) {
+		iTrack = pSession->tracks().find(pTrack);
+	}
+	qtractorMidiController *pMidiController
+		= qtractorMidiController::getInstance();
+	if (pMidiController) {
+		pMidiController->processCommand(
+			qtractorMidiController::TRACKPAN, iTrack, m_fPanning);
+	}
+
 	// Set undo value...
 	m_bPrevPanning = false;
 	m_fPrevPanning = m_fPanning;
diff -duPNr qtractor.0/win32/qtractor.pro qtractor.1/win32/qtractor.pro
--- qtractor.0/win32/qtractor.pro	2009-02-08 15:12:58.000000000 +0000
+++ qtractor.1/win32/qtractor.pro	2009-05-07 19:09:23.000000000 +0100
@@ -35,6 +35,7 @@
            ../src/qtractorMidiBuffer.h \
            ../src/qtractorMidiClip.h \
            ../src/qtractorMidiConnect.h \
+           ../src/qtractorMidiController.h \
            ../src/qtractorMidiCursor.h \
            ../src/qtractorMidiEditor.h \
            ../src/qtractorMidiEditCommand.h \
@@ -130,6 +131,7 @@
            ../src/qtractorMidiBuffer.cpp \
            ../src/qtractorMidiClip.cpp \
            ../src/qtractorMidiConnect.cpp \
+           ../src/qtractorMidiController.cpp \
            ../src/qtractorMidiCursor.cpp \
            ../src/qtractorMidiEditor.cpp \
            ../src/qtractorMidiEditCommand.cpp \
