View Issue Details

IDProjectCategoryView StatusLast Update
0003613ardourbugspublic2020-04-19 20:15
Reporternowhiskey Assigned Topaul  
PrioritynormalSeverityminorReproducibilityhave not tried
Status closedResolutionfixed 
Target Version3.X 
Summary0003613: wiimote control does not compile in A3
Descriptionin rev8287 enabling wiimote control in ./waf configure is causing the build process to fall. this is the output:

   1.
      [410/697] cxx: libs/surfaces/wiimote/wiimote.cc -> build/default/libs/surfaces/wiimote/wiimote_1.o
   2.
      In file included from ../libs/surfaces/wiimote/wiimote.cc:1:
   3.
      ../libs/pbd/pbd/stateful.h:50:14: warning: 'virtual int PBD::Stateful::set_state(const XMLNode&, int)' was hidden
   4.
      ../libs/surfaces/wiimote/wiimote.h:37:7: warning: by 'int WiimoteControlProtocol::set_state(const XMLNode&)'
   5.
      ../libs/surfaces/wiimote/wiimote.cc: In constructor 'WiimoteControlProtocol::WiimoteControlProtocol(ARDOUR::Session&)':
   6.
      ../libs/surfaces/wiimote/wiimote.cc:24:21: error: no matching function for call to 'ARDOUR::ControlProtocol::ControlProtocol(ARDOUR::Session&, const char [8])'
   7.
      ../libs/surfaces/control_protocol/control_protocol/control_protocol.h:121:2: note: candidates are: ARDOUR::ControlProtocol::ControlProtocol(const ARDOUR::ControlProtocol&)
   8.
      ../libs/surfaces/control_protocol/control_protocol/control_protocol.h:40:2: note: ARDOUR::ControlProtocol::ControlProtocol(ARDOUR::Session&, std::string, PBD::EventLoop*)
   9.
      ../libs/surfaces/wiimote/wiimote.cc: At global scope:
  10.
      ../libs/surfaces/wiimote/wiimote.cc:169:40: error: no 'void WiimoteControlProtocol::_wiimote_main()' member function declared in class 'WiimoteControlProtocol'
  11.
      Waf: Leaving directory `/home/nowhiskey/Desktop/src/3.0/build'
  12.
      Build failed: -> task failed (err 0000001):
  13.
              {task: cxx wiimote.cc -> wiimote_1.o}
  14.
      nowhiskey@murija5:~/Desktop/src/3.0$


perhaps easyer to read here:

http://pastebin.com/VJ0hxVZ9


cheers,
doc
TagsNo tags attached.

Activities

paul

2011-01-29 00:56

administrator   ~0009981

i've notified sampo (the author of wiimote support) of this. until someone is motivated to port it over, this is going to remain a problem.

2012-10-02 23:01

 

0001-wiimote-link-against-cwiid-library.patch (1,759 bytes)   
From 58338f40c920aa06ea1a7e8b93835b8029a0c407 Mon Sep 17 00:00:00 2001
From: Jannis Pohlmann <jannis@xfce.org>
Date: Sat, 8 Sep 2012 11:00:03 +0100
Subject: [PATCH 1/6] wiimote: link against cwiid library

---
 libs/surfaces/wiimote/wscript | 9 +++++----
 libs/surfaces/wscript         | 2 ++
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/libs/surfaces/wiimote/wscript b/libs/surfaces/wiimote/wscript
index 3fbea7e..3a4bd10 100644
--- a/libs/surfaces/wiimote/wscript
+++ b/libs/surfaces/wiimote/wscript
@@ -26,10 +26,11 @@ def build(bld):
     '''
     obj.export_includes = ['./wiimote']
     obj.cxxflags     = '-DPACKAGE="ardour_wiimote"'
-    obj.includes     = ['.', './wiimote']
-    obj.name         = 'libwiimote'
-    obj.target       = 'wiimote'
-    obj.use          = 'libardour libardour_cp'
+    obj.includes     = ['.', '../libs']
+    obj.name         = 'libardour_wiimote'
+    obj.target       = 'ardour_wiimote'
+    obj.uselib       = 'GTKMM CWIID'
+    obj.use          = 'libardour libardour_cp libgtkmm2ext'
     obj.vnum         = LIBARDOUR_WIIMOTE_LIB_VERSION
     obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'surfaces')
 
diff --git a/libs/surfaces/wscript b/libs/surfaces/wscript
index 5777034..8dfc0d8 100644
--- a/libs/surfaces/wscript
+++ b/libs/surfaces/wscript
@@ -60,6 +60,8 @@ def configure(conf):
         if not conf.is_defined('HAVE_BLUETOOTH_H'):
             print('WIIMOTE configured but you are missing the libbluetooth headers needed to compile wiimote support!')
             sys.exit(1)
+        autowaf.check_pkg(conf, 'cwiid', uselib_store='CWIID',
+                          atleast_version='0.6.00')
         conf.define ('BUILD_WIIMOTE', 1)
 
 def build(bld):
-- 
1.7.11.4

2012-10-02 23:01

 

0002-wiimote-add-new-PBD-DEBUG-WiimoteControl-debug-bit.patch (1,190 bytes)   
From 094905a1b3232001ab98962b00f3f5200d1669c6 Mon Sep 17 00:00:00 2001
From: Jannis Pohlmann <jannis@xfce.org>
Date: Sat, 8 Sep 2012 11:03:09 +0100
Subject: [PATCH 2/6] wiimote: add new PBD::DEBUG::WiimoteControl debug bit

---
 libs/ardour/ardour/debug.h | 1 +
 libs/ardour/debug.cc       | 1 +
 2 files changed, 2 insertions(+)

diff --git a/libs/ardour/ardour/debug.h b/libs/ardour/ardour/debug.h
index 334aac5..e97ae79 100644
--- a/libs/ardour/ardour/debug.h
+++ b/libs/ardour/ardour/debug.h
@@ -61,6 +61,7 @@ namespace PBD {
 		extern uint64_t TempoMap;
 		extern uint64_t OrderKeys;
 		extern uint64_t Automation;
+		extern uint64_t WiimoteControl;
 	}
 }
 
diff --git a/libs/ardour/debug.cc b/libs/ardour/debug.cc
index 0d0948d..46da707 100644
--- a/libs/ardour/debug.cc
+++ b/libs/ardour/debug.cc
@@ -58,5 +58,6 @@ uint64_t PBD::DEBUG::TempoMath = PBD::new_debug_bit ("tempomath");
 uint64_t PBD::DEBUG::TempoMap = PBD::new_debug_bit ("tempomap");
 uint64_t PBD::DEBUG::OrderKeys = PBD::new_debug_bit ("orderkeys");
 uint64_t PBD::DEBUG::Automation = PBD::new_debug_bit ("automation");
+uint64_t PBD::DEBUG::WiimoteControl = PBD::new_debug_bit ("wiimotecontrol");
 
 
-- 
1.7.11.4

2012-10-02 23:01

 

0003-wiimote-port-to-AbstractUI-use-IdleSource-for-receiv.patch (20,617 bytes)   
From 15c94967170f211ae2939d616bdd16a7f502492a Mon Sep 17 00:00:00 2001
From: Jannis Pohlmann <jannis@xfce.org>
Date: Fri, 7 Sep 2012 21:26:29 +0100
Subject: [PATCH 3/6] wiimote: port to AbstractUI, use IdleSource for
 receiving messages

---
 libs/surfaces/wiimote/interface.cc |  42 +---
 libs/surfaces/wiimote/wiimote.cc   | 479 +++++++++++++++++++++----------------
 libs/surfaces/wiimote/wiimote.h    |  84 +++----
 3 files changed, 310 insertions(+), 295 deletions(-)

diff --git a/libs/surfaces/wiimote/interface.cc b/libs/surfaces/wiimote/interface.cc
index 5f622d5..904855f 100644
--- a/libs/surfaces/wiimote/interface.cc
+++ b/libs/surfaces/wiimote/interface.cc
@@ -1,47 +1,25 @@
-#include <pbd/failed_constructor.h>
+#include "pbd/failed_constructor.h"
+#include "pbd/error.h"
 
+#include "ardour/session.h"
 #include "control_protocol/control_protocol.h"
-#include "wiimote.h"
 
-#include "ardour/session.h"
+#include "wiimote.h"
 
 using namespace ARDOUR;
-
-static WiimoteControlProtocol *foo;
+using namespace PBD;
 
 ControlProtocol*
 new_wiimote_protocol (ControlProtocolDescriptor* descriptor, Session* s)
 {
-	WiimoteControlProtocol* wmcp;
-		
-	try {
-		wmcp =  new WiimoteControlProtocol (*s);
-	} catch (failed_constructor& err) {
-		return 0;
-	}
-	
-	if (wmcp-> set_active (true)) {
-		delete wmcp;
-		return 0;
-	}
-
-	foo = wmcp;
-
+	WiimoteControlProtocol* wmcp = new WiimoteControlProtocol (*s);
+	wmcp->set_active (true);
 	return wmcp;
 }
 
 void
-wiimote_control_protocol_cwiid_callback(cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg[], struct timespec *t)
-{
-	assert(foo != 0);
-
-	foo->wiimote_callback(wiimote,mesg_count,mesg,t);
-}
-
-void
 delete_wiimote_protocol (ControlProtocolDescriptor* descriptor, ControlProtocol* cp)
 {
-	foo = 0;
 	delete cp;
 }
 
@@ -62,12 +40,14 @@ static ControlProtocolDescriptor wiimote_descriptor = {
 	initialize : new_wiimote_protocol,
 	destroy : delete_wiimote_protocol
 };
-	
+
 
 extern "C" {
-ControlProtocolDescriptor* 
+
+ControlProtocolDescriptor*
 protocol_descriptor () {
 	return &wiimote_descriptor;
 }
+
 }
 
diff --git a/libs/surfaces/wiimote/wiimote.cc b/libs/surfaces/wiimote/wiimote.cc
index 26f7e18..445ac50 100644
--- a/libs/surfaces/wiimote/wiimote.cc
+++ b/libs/surfaces/wiimote/wiimote.cc
@@ -1,291 +1,346 @@
-#include "wiimote.h"
-
 #include <iostream>
-#include <sigc++/bind.h>
 
-#include "pbd/xml++.h"
+#include "pbd/compose.h"
+#include "pbd/error.h"
+#include "ardour/debug.h"
 #include "ardour/session.h"
-
 #include "i18n.h"
 
+#include "wiimote.h"
 
 using namespace ARDOUR;
 using namespace PBD;
+using namespace std;
 
-void wiimote_control_protocol_cwiid_callback(cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg[], struct timespec *t);
-
-uint16_t WiimoteControlProtocol::button_state = 0;
+#include "pbd/abstract_ui.cc" // instantiate template
 
-WiimoteControlProtocol::WiimoteControlProtocol ( Session & session) 
-	: ControlProtocol ( session, "Wiimote"),
-	  main_thread_quit (false),
-	  restart_discovery (false),
-	  callback_thread_registered_for_ardour (false),
-	  wiimote_handle (0)
+WiimoteControlProtocol::WiimoteControlProtocol (Session& session)
+	: ControlProtocol (session, X_("Wiimote"))
+	, AbstractUI<WiimoteControlUIRequest> ("wiimote")
+	, wiimote (0)
+	, idle_source (0)
+	, button_state (0)
 {
-	main_thread = Glib::Thread::create( sigc::mem_fun(*this, &WiimoteControlProtocol::wiimote_main), true);
 }
 
-WiimoteControlProtocol::~WiimoteControlProtocol()
+WiimoteControlProtocol::~WiimoteControlProtocol ()
 {
-	main_thread_quit = true;
-	slot_cond.signal();
-	main_thread->join();
-
-	if (wiimote_handle) {
-		cwiid_close(wiimote_handle);
-	}
-
-	std::cerr << "Wiimote: closed" << std::endl;
+	// FIXME this causes Ardour to hang on exit
+	stop ();
 }
 
 bool 
-WiimoteControlProtocol::probe()
+WiimoteControlProtocol::probe ()
 {
 	return true;
 }
 
-void
-WiimoteControlProtocol::wiimote_callback(cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg[], struct timespec *t)
+int
+WiimoteControlProtocol::set_active (bool yn)
 {
-	int i;
-	uint16_t b;
+	int result;
 
-	if (!callback_thread_registered_for_ardour) {
-		register_thread("Wiimote Control Protocol");
-		callback_thread_registered_for_ardour = true;
-	}
+	DEBUG_TRACE (DEBUG::WiimoteControl, string_compose ("WiimoteControlProtocol::set_active init with yn: '%1'\n", yn));
 
-        for (i=0; i < mesg_count; i++)
-	{
-		if (mesg[i].type == CWIID_MESG_ERROR) {	
-			std::cerr << "Wiimote: disconnect" << std::endl;
-			restart_discovery = true;
-			slot_cond.signal();
-			return;
-		}
+	/* do nothing if the active state is not changing */
+	if (yn == _active) {
+		return 0;
+	}
 
-		if (mesg[i].type != CWIID_MESG_BTN) continue;
+	if (yn) {
+		/* activate Wiimote control surface */
+		result = start ();
+	} else {
+		/* deactivate Wiimote control surface */
+		result = stop ();
+	}
 
-		// what buttons are pressed down which weren't pressed down last time
-		b = (mesg[i].btn_mesg.buttons ^ button_state) & mesg[i].btn_mesg.buttons;
+	/* remember new active state */
+	_active = yn;
 
-		button_state = mesg[i].btn_mesg.buttons;
-	
-		// if B is pressed down
-		if (button_state & CWIID_BTN_B) {
-			if (b & CWIID_BTN_A) { // B is down and A is pressed
-				access_action("Transport/ToggleRollForgetCapture");
-			}
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::set_active done\n");
 
-			if (b & CWIID_BTN_LEFT) {
-				access_action("Editor/playhead-to-previous-region-boundary");
-			}
-			if (b & CWIID_BTN_RIGHT) {
-				access_action("Editor/playhead-to-next-region-boundary");
-			}
-			if (b & CWIID_BTN_UP) {
-				next_marker();
-			}
-			if (b & CWIID_BTN_DOWN) {
-				prev_marker();
-			}
-
-			if (b & CWIID_BTN_HOME) {
-				access_action("Editor/add-location-from-playhead");
-			}
+	return result;
+}
 
-			if (b & CWIID_BTN_MINUS) {	
-				access_action("Transport/GotoStart");
-			}
-			
-			if (b & CWIID_BTN_PLUS) {
-				access_action("Transport/GotoEnd");
-			}
+XMLNode&
+WiimoteControlProtocol::get_state ()
+{
+	XMLNode *node = new XMLNode ("Protocol");
+	node->add_property (X_("name"), ARDOUR::ControlProtocol::_name);
+	node->add_property (X_("feedback"), "0");
+	return *node;
+}
 
-			continue;
-		}
+int
+WiimoteControlProtocol::set_state (const XMLNode& node, int version)
+{
+	return 0;
+}
 
+void
+WiimoteControlProtocol::do_request (WiimoteControlUIRequest* req)
+{
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::do_request init\n");
 
-		if (b & CWIID_BTN_A) {
-			access_action("Transport/ToggleRoll");
-		}
+	if (req->type == CallSlot) {
+		call_slot (MISSING_INVALIDATOR, req->the_slot);
+	} else if (req->type == Quit) {
+		stop ();
+	}
 
-		if (b & CWIID_BTN_1) { // 1
-			access_action("Editor/track-record-enable-toggle");
-		}
-		if (b & CWIID_BTN_2) { // 2
-			rec_enable_toggle();
-		}
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::do_request done\n");
+}
 
-		// d-pad
-		if (b & CWIID_BTN_LEFT) { // left
-			access_action("Editor/nudge-playhead-backward");
-		}
-		if (b & CWIID_BTN_RIGHT) { // right
-			access_action("Editor/nudge-playhead-forward");
-		}
-		if (b & CWIID_BTN_DOWN) { // down
-			access_action("Editor/select-next-route");
-		}
-		if (b & CWIID_BTN_UP) { // up
-			access_action("Editor/select-prev-route");
-		}
+int
+WiimoteControlProtocol::start ()
+{
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::start init\n");
 
+	// start the Wiimote control UI; it will run in its own thread context
+	BaseUI::run ();
 
-		if (b & CWIID_BTN_PLUS) { // +
-			access_action("Editor/temporal-zoom-in");
-		}
-		if (b & CWIID_BTN_MINUS) { // -
-			access_action("Editor/temporal-zoom-out");
-		}
-		if (b & CWIID_BTN_HOME) { // "home"
-			// no op, yet. any suggestions?
-			access_action("Editor/playhead-to-edit");
-		}
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::start done\n");
 
-	}
+	return 0;
 }
 
-void
-WiimoteControlProtocol::update_led_state()
+int
+WiimoteControlProtocol::stop ()
 {
-	ENSURE_WIIMOTE_THREAD(sigc::mem_fun(*this, &WiimoteControlProtocol::update_led_state));
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::stop init\n");
 
-	uint8_t state = 0;
+	// release the idle source used for checking for incoming messages
+	g_source_destroy (idle_source);
+	g_source_unref (idle_source);
+	idle_source = 0;
 
-	if (session->transport_rolling()) {
-		state |= CWIID_LED1_ON;
-	}
+	// stop the Wiimote control UI
+	BaseUI::quit ();
 
-	if (session->actively_recording()) {
-		state |= CWIID_LED4_ON;
-	}
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::stop done\n");
 
-	cwiid_set_led(wiimote_handle, state);
+	return 0;
 }
 
 void
-WiimoteControlProtocol::_wiimote_main ()
+WiimoteControlProtocol::thread_init ()
 {
-	bdaddr_t bdaddr;
-	unsigned char rpt_mode = 0;
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::thread_init init\n");
 
-	register_thread ("Wiimote");
+	pthread_set_name (X_("wiimote"));
 
-wiimote_discovery:
+	// allow to make requests to the GUI and RT thread(s)
+	PBD::notify_gui_about_thread_creation (X_("gui"), pthread_self (), X_("wiimote"), 2048);
+	SessionEvent::create_per_thread_pool (X_("wiimote"), 128);
 
-	std::cerr << "Wiimote: discovering, press 1+2" << std::endl;
+	// set up an idle source to check for incoming messages from the Wiimote
+	Glib::RefPtr<Glib::IdleSource> source = Glib::IdleSource::create ();
+	source->connect (sigc::mem_fun (*this, &WiimoteControlProtocol::idle));
+	source->attach (_main_loop->get_context ());
 
- 	while (!wiimote_handle && !main_thread_quit) {
-		bdaddr = (bdaddr_t) {{0, 0, 0, 0, 0, 0}};
-		callback_thread_registered_for_ardour = false;
-		wiimote_handle = cwiid_open(&bdaddr, 0);
+	// grab a reference on the underlying idle source to keep it around
+	idle_source = source->gobj ();
+	g_source_ref (idle_source);
 
-		if (!wiimote_handle && !main_thread_quit) {
-			sleep(1); 
-			// We don't know whether the issue was a timeout or a configuration 
-			// issue
-		}
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::thread_init done\n");
+}
+
+bool
+WiimoteControlProtocol::idle ()
+{
+	// if the Wiimote is not connected, ask the user to connect it now;
+	// if that fails, try again by calling the idle source again
+	if (!connect_wiimote ()) {
+		sleep (1);
+		return TRUE;
 	}
 
-	if (main_thread_quit) {
-		// The corner case where the wiimote is bound at the same time as
-		// the control protocol is destroyed
-		if (wiimote_handle) {
-			cwiid_close(wiimote_handle);
+	int i;
+	int mesg_count;
+	union cwiid_mesg *mesg;
+	struct timespec timestamp;
+
+	cwiid_get_mesg (wiimote, &mesg_count, &mesg, &timestamp);
+
+	for (i = 0; i < mesg_count; i++) {
+		// reset the Wiimote handle when receiving errors, so that the user
+		// is asked to reconnect it when the idle source is called next time
+		if (mesg[i].type == CWIID_MESG_ERROR) {
+			cerr << "Wiimote: disconnected" << endl;
+			if (wiimote) {
+				cwiid_close (wiimote);
+				wiimote = 0;
+			}
+			return TRUE;
 		}
-		wiimote_handle = 0;
 
-		std::cerr << "Wiimote Control Protocol stopped before connected to a wiimote" << std::endl;
-		return;
-	}
+		// skip non-button events
+		if (mesg[i].type != CWIID_MESG_BTN) {
+			continue;
+		}
 
-	std::cerr << "Wiimote: connected" << std::endl;
-	WiimoteControlProtocol::button_state = 0;
+		// drop buttons from the event that were already pressed before
+		uint16_t b = mesg[i].btn_mesg.buttons & ~button_state;
 
-	if (cwiid_enable(wiimote_handle, CWIID_FLAG_REPEAT_BTN)) {
-		std::cerr << "cwiid_enable(), error" << std::endl;
-		cwiid_close(wiimote_handle);
-		wiimote_handle = 0;
-		return;
-	}
-	if (cwiid_set_mesg_callback(wiimote_handle, wiimote_control_protocol_cwiid_callback)) {
-		std::cerr << "cwiid_set_mesg_callback(), couldn't connect callback" << std::endl;
-		cwiid_close(wiimote_handle);
-		wiimote_handle = 0;
-		return;
-	} 
-	if (cwiid_command(wiimote_handle, CWIID_CMD_RPT_MODE, CWIID_RPT_BTN)) {
-		std::cerr << "cwiid_command(), RPT_MODE error" << std::endl;
-		cwiid_close(wiimote_handle);
-		wiimote_handle = 0;
-		return;
-	}
+		// remember new button state
+		button_state = mesg[i].btn_mesg.buttons;
 
-	rpt_mode |= CWIID_RPT_BTN;
-	cwiid_enable(wiimote_handle, CWIID_FLAG_MESG_IFC);
-	cwiid_set_rpt_mode(wiimote_handle, rpt_mode);
+		if (button_state & CWIID_BTN_B) {
+			// B + A = abort recording and jump back
+			if (b & CWIID_BTN_A) {
+				access_action ("Transport/ToggleRollForgetCapture");
+			}
 
-	transport_state_conn = session->TransportStateChange.connect(sigc::mem_fun(*this, &WiimoteControlProtocol::update_led_state));
-	record_state_conn = session->RecordStateChanged.connect(sigc::mem_fun(*this, &WiimoteControlProtocol::update_led_state));
+			// B + left = move playhead to previous region boundary
+			if (b & CWIID_BTN_LEFT) {
+				access_action ("Editor/playhead-to-previous-region-boundary");
+			}
 
-	std::cerr << "Wiimote: initialization done, waiting for callbacks / quit" << std::endl;
+			// B + right = move playhead to next region boundary
+			if (b & CWIID_BTN_RIGHT) {
+				access_action ("Editor/playhead-to-next-region-boundary");
+			}
 
-	while (!main_thread_quit) {
-		slot_mutex.lock();
-		while (slot_list.empty() && !main_thread_quit && !restart_discovery)
-			slot_cond.wait(slot_mutex);
+			// B + up = move playhead to next marker
+			if (b & CWIID_BTN_UP) {
+				next_marker ();
+			}
 
-		if (main_thread_quit) {
-			slot_mutex.unlock();
-			break;
-		}
+			// B + down = move playhead to prev marker
+			if (b & CWIID_BTN_DOWN) {
+				prev_marker ();
+			}
 
-		if (restart_discovery) {
-			std::cerr << "Wiimote: closing wiimote and restarting discovery" << std::endl;
-			if (wiimote_handle) {
-				cwiid_close(wiimote_handle);
-				wiimote_handle = 0;
+			// B + Home = add marker at playhead
+			if (b & CWIID_BTN_HOME) {
+				access_action ("Editor/add-location-from-playhead");
 			}
-			slot_mutex.unlock();
-			restart_discovery = false;
-			goto wiimote_discovery;
-		}
 
-		sigc::slot<void> call_me = *slot_list.begin();
-		slot_list.pop_front();
-		slot_mutex.unlock();
+			// B + minus = move playhead to the start
+			if (b & CWIID_BTN_MINUS) {
+				access_action ("Transport/GotoStart");
+			}
 
-		call_me();
-	}
+			// B + plus = move playhead to the end
+			if (b & CWIID_BTN_PLUS) {
+				access_action ("Transport/GotoEnd");
+			}
+		} else {
+			// A = toggle playback
+			if (b & CWIID_BTN_A) {
+				access_action ("Transport/ToggleRoll");
+			}
 
+			// 1 = toggle recording on the current track
+			if (b & CWIID_BTN_1) {
+				access_action ("Editor/track-record-enable-toggle");
+			}
 
-	std::cerr << "Wiimote: main thread stopped" << std::endl;
-	return 0;
-}
+			// 2 = enable recording in general
+			if (b & CWIID_BTN_2) {
+				rec_enable_toggle ();
+			}
 
+			// left = move playhead back a bit
+			if (b & CWIID_BTN_LEFT) {
+				access_action ("Editor/nudge-playhead-backward");
+			}
 
-int
-WiimoteControlProtocol::set_active (bool yn)
-{
-	// Let's not care about this just yet
-	return 0;
+			// right = move playhead forward a bit
+			if (b & CWIID_BTN_RIGHT) {
+				access_action ("Editor/nudge-playhead-forward");
+			}
 
-}
+			// up = select previous track
+			if (b & CWIID_BTN_UP) {
+				access_action ("Editor/select-prev-route");
+			}
 
-XMLNode&
-WiimoteControlProtocol::get_state()
-{
-	XMLNode *node = new XMLNode ("Protocol");
-        node->add_property (X_("name"), _name);
-        node->add_property (X_("feedback"), "0");
+			// down = select next track
+			if (b & CWIID_BTN_DOWN) {
+				access_action ("Editor/select-next-route");
+			}
 
-	return *node;
+			// + = zoom in
+			if (b & CWIID_BTN_PLUS) {
+				access_action ("Editor/temporal-zoom-in");
+			}
+
+			// - = zoom out
+			if (b & CWIID_BTN_MINUS) {
+				access_action ("Editor/temporal-zoom-out");
+			}
+
+			// home = no-op
+			if (b & CWIID_BTN_HOME) {
+				access_action ("Editor/playhead-to-edit");
+			}
+		}
+	}
+
+	return TRUE;
 }
 
-int
-WiimoteControlProtocol::set_state(const XMLNode& node)
+bool
+WiimoteControlProtocol::connect_wiimote ()
 {
-	return 0;
+	// do nothing if we already have a Wiimote
+	if (wiimote) {
+		return true;
+	}
+
+	bool success = true;
+
+	// if we don't have a Wiimote yet, try to discover it; if that
+	// fails, wait for a short period of time and try again
+	if (!wiimote) {
+		cerr << "Wiimote: Not discovered yet, press 1+2 to connect" << endl;
+
+		bdaddr_t bdaddr = {{ 0, 0, 0, 0, 0, 0 }};
+		wiimote = cwiid_open (&bdaddr, 0);
+		if (!wiimote) {
+			success = false;
+		} else {
+			// a Wiimote was discovered
+			cerr << "Wiimote: Connected successfully" << endl;
+
+			// attach the WiimoteControlProtocol object to the Wiimote handle
+			if (cwiid_set_data (wiimote, this)) {
+				cerr << "Wiimote: Failed to attach control protocol" << endl;
+				success = false;
+			}
+
+			// clear the last button state to start processing events cleanly
+			button_state = 0;
+		}
+	}
+
+	// enable message based communication with the Wiimote
+	if (success && cwiid_enable (wiimote, CWIID_FLAG_MESG_IFC)) {
+		cerr << "Wiimote: Failed to enable message based communication" << endl;
+		success = false;
+	}
+
+	// enable button events to be received from the Wiimote
+	if (success && cwiid_command (wiimote, CWIID_CMD_RPT_MODE, CWIID_RPT_BTN)) {
+		cerr << "Wiimote: Failed to enable button events" << endl;
+		success = false;
+	}
+
+	// receive an event for every single button pressed, not just when
+	// a different button was pressed than before
+	if (success && cwiid_enable (wiimote, CWIID_FLAG_REPEAT_BTN)) {
+		cerr << "Wiimote: Failed to enable repeated button events" << endl;
+		success = false;
+	}
+
+	// reset Wiimote handle if the configuration failed
+	if (!success && wiimote) {
+		cwiid_close (wiimote);
+		wiimote = 0;
+	}
+
+	return success;
 }
+
diff --git a/libs/surfaces/wiimote/wiimote.h b/libs/surfaces/wiimote/wiimote.h
index 4ab1974..e0dec14 100644
--- a/libs/surfaces/wiimote/wiimote.h
+++ b/libs/surfaces/wiimote/wiimote.h
@@ -1,69 +1,49 @@
 #ifndef ardour_wiimote_control_protocol_h
 #define ardour_wiimote_control_protocol_h
 
+#include <cwiid.h>
+
+#include "pbd/abstract_ui.h"
 #include "ardour/types.h"
 #include "control_protocol/control_protocol.h"
 
-#include <glibmm/threads.h>
+struct WiimoteControlUIRequest : public BaseUI::BaseRequestObject {
+public:
+	WiimoteControlUIRequest () {}
+	~WiimoteControlUIRequest () {}
+};
+
+class WiimoteControlProtocol
+	: public ARDOUR::ControlProtocol
+	, public AbstractUI<WiimoteControlUIRequest>
+{
+public:
+	WiimoteControlProtocol (ARDOUR::Session &);
+	virtual ~WiimoteControlProtocol ();
 
-#include "pbd/abstract_ui.h"
+	static bool probe ();
+	int set_active (bool yn);
 
-#include <cwiid.h>
+	XMLNode& get_state ();
+	int set_state (const XMLNode&, int version);
 
+	void wiimote_callback (cwiid_wiimote_t* wiimote, int mesg_count, union cwiid_mesg msg[], struct timespec* t);
 
-namespace ARDOUR {
-        class Session;
-}
+protected:
+	void do_request (WiimoteControlUIRequest*);
+	int start ();
+	int stop ();
 
-#define ENSURE_WIIMOTE_THREAD(slot) \
-	if (Glib::Threads::Thread::self() != main_thread) {	\
-		slot_mutex.lock();\
-		slot_list.push_back(slot);\
-		slot_cond.signal();\
-		slot_mutex.unlock();\
-		return;\
-	} 
+	void thread_init ();
 
+	bool idle ();
+	bool connect_wiimote ();
 
-class WiimoteControlProtocol : public ARDOUR::ControlProtocol {
-  public:
-    WiimoteControlProtocol (ARDOUR::Session &);
-    virtual ~WiimoteControlProtocol ();
-    
-    static bool probe();
-    
-    int set_active (bool yn);
-    XMLNode& get_state();
-    int set_state(const XMLNode&);
-    
-    void wiimote_callback(cwiid_wiimote_t *, int, union cwiid_mesg [], 
-			  struct timespec *);
-    
-  private:
-    
-    void wiimote_main();
-    volatile bool main_thread_quit;
-    volatile bool restart_discovery;
-    
-    Glib::Threads::Thread *main_thread;
-    
-    void update_led_state();
-    
-    bool callback_thread_registered_for_ardour;
-    
-    static uint16_t button_state;
-    
-    cwiid_wiimote_t *wiimote_handle;
-    
-    Glib::Threads::Cond slot_cond;
-    Glib::Threads::Mutex slot_mutex;
-    
-    std::list< sigc::slot<void> > slot_list;
-    
-    sigc::connection transport_state_conn;
-    sigc::connection record_state_conn;
+protected:
+	cwiid_wiimote_t* wiimote;
+	GSource *idle_source;
+	uint16_t button_state;
 };
 
-
 #endif  /* ardour_wiimote_control_protocol_h */
 
-- 
1.7.11.4

2012-10-02 23:01

 

0004-wiimote-update-LEDs-on-transport-recording-state-cha.patch (3,109 bytes)   
From bd95b5060ec8963e6bb59a22e51434472a83cc52 Mon Sep 17 00:00:00 2001
From: Jannis Pohlmann <jannis@xfce.org>
Date: Tue, 11 Sep 2012 17:33:37 +0100
Subject: [PATCH 4/6] wiimote: update LEDs on transport/recording state
 changes again

---
 libs/surfaces/wiimote/wiimote.cc | 39 ++++++++++++++++++++++++++++++++++++++-
 libs/surfaces/wiimote/wiimote.h  |  3 +++
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/libs/surfaces/wiimote/wiimote.cc b/libs/surfaces/wiimote/wiimote.cc
index 445ac50..97c7d03 100644
--- a/libs/surfaces/wiimote/wiimote.cc
+++ b/libs/surfaces/wiimote/wiimote.cc
@@ -29,7 +29,7 @@ WiimoteControlProtocol::~WiimoteControlProtocol ()
 	stop ();
 }
 
-bool 
+bool
 WiimoteControlProtocol::probe ()
 {
 	return true;
@@ -97,6 +97,10 @@ WiimoteControlProtocol::start ()
 {
 	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::start init\n");
 
+	// update LEDs whenever the transport or recording state changes
+	session->TransportStateChange.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&WiimoteControlProtocol::update_led_state, this), this);
+	session->RecordStateChanged.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&WiimoteControlProtocol::update_led_state, this), this);
+
 	// start the Wiimote control UI; it will run in its own thread context
 	BaseUI::run ();
 
@@ -118,6 +122,9 @@ WiimoteControlProtocol::stop ()
 	// stop the Wiimote control UI
 	BaseUI::quit ();
 
+	// no longer update the LEDs
+	session_connections.drop_connections ();
+
 	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::stop done\n");
 
 	return 0;
@@ -344,3 +351,33 @@ WiimoteControlProtocol::connect_wiimote ()
 	return success;
 }
 
+void
+WiimoteControlProtocol::update_led_state ()
+{
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state init\n");
+
+	uint8_t state = 0;
+
+	// do nothing if we do not have a Wiimote
+	if (!wiimote) {
+		DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state no wiimote connected\n");
+		return;
+	}
+
+	// enable LED1 if Ardour is playing
+	if (session->transport_rolling ()) {
+		DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state playing, activate LED1\n");
+		state |= CWIID_LED1_ON;
+	}
+
+	// enable LED4 if Ardour is recording
+	if (session->actively_recording ()) {
+		DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state recording, activate LED4\n");
+		state |= CWIID_LED4_ON;
+	}
+
+	// apply the LED state
+	cwiid_set_led (wiimote, state);
+
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state done\n");
+}
diff --git a/libs/surfaces/wiimote/wiimote.h b/libs/surfaces/wiimote/wiimote.h
index e0dec14..2a2db7a 100644
--- a/libs/surfaces/wiimote/wiimote.h
+++ b/libs/surfaces/wiimote/wiimote.h
@@ -39,7 +39,10 @@ protected:
 	bool idle ();
 	bool connect_wiimote ();
 
+	void update_led_state ();
+
 protected:
+	PBD::ScopedConnectionList session_connections;
 	cwiid_wiimote_t* wiimote;
 	GSource *idle_source;
 	uint16_t button_state;
-- 
1.7.11.4

2012-10-02 23:01

 

0005-wiimote-add-wiimote-surface-to-ardev_common.sh-for-d.patch (1,186 bytes)   
From 164a1e461684a8fa5c0eb324a2ccf9c51fd7571a Mon Sep 17 00:00:00 2001
From: Jannis Pohlmann <jannis@xfce.org>
Date: Sat, 29 Sep 2012 16:47:23 +0100
Subject: [PATCH 5/6] wiimote: add wiimote surface to ardev_common.sh for
 debugging

---
 gtk2_ardour/ardev_common.sh.in | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gtk2_ardour/ardev_common.sh.in b/gtk2_ardour/ardev_common.sh.in
index 210f282..2a8e23d 100644
--- a/gtk2_ardour/ardev_common.sh.in
+++ b/gtk2_ardour/ardev_common.sh.in
@@ -12,7 +12,7 @@ libs=$TOP/@LIBS@
 
 
 export ARDOUR_PATH=$TOP/gtk2_ardour/icons:$TOP/gtk2_ardour/pixmaps:$TOP/build/gtk2_ardour:$TOP/gtk2_ardour:.
-export ARDOUR_SURFACES_PATH=$libs/surfaces/osc:$libs/surfaces/generic_midi:$libs/surfaces/tranzport:$libs/surfaces/powermate:$libs/surfaces/mackie
+export ARDOUR_SURFACES_PATH=$libs/surfaces/osc:$libs/surfaces/generic_midi:$libs/surfaces/tranzport:$libs/surfaces/powermate:$libs/surfaces/mackie:$libs/surfaces/wiimote
 export ARDOUR_PANNER_PATH=$libs/panners/2in2out:$libs/panners/1in2out:$libs/panners/vbap
 export ARDOUR_DATA_PATH=$TOP/gtk2_ardour:build/gtk2_ardour:.
 export ARDOUR_MIDIMAPS_PATH=$TOP/midi_maps:.
-- 
1.7.11.4

2012-10-02 23:02

 

0006-wiimote-rework-discovery-use-callback-for-receiving-.patch (11,723 bytes)   
From bcfd530966b20afb9cf81915d28c74284c1d80ca Mon Sep 17 00:00:00 2001
From: Jannis Pohlmann <jannis@xfce.org>
Date: Sat, 29 Sep 2012 17:20:48 +0100
Subject: [PATCH 6/6] wiimote: rework discovery, use callback for receiving
 input events

Thanks to this, a permanent idle source for establishing the connection
to a Wiimote and receiving messages with a blocking function call is no
longer necessary. This fixes a problem where closing Ardour or turning
off the Wiimote surface caused Ardour to freeze.
---
 libs/surfaces/wiimote/wiimote.cc | 273 +++++++++++++++++++++++----------------
 libs/surfaces/wiimote/wiimote.h  |   7 +-
 2 files changed, 165 insertions(+), 115 deletions(-)

diff --git a/libs/surfaces/wiimote/wiimote.cc b/libs/surfaces/wiimote/wiimote.cc
index 97c7d03..879ef67 100644
--- a/libs/surfaces/wiimote/wiimote.cc
+++ b/libs/surfaces/wiimote/wiimote.cc
@@ -14,6 +14,8 @@ using namespace std;
 
 #include "pbd/abstract_ui.cc" // instantiate template
 
+void wiimote_control_protocol_mesg_callback (cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg[], timespec *t);
+
 WiimoteControlProtocol::WiimoteControlProtocol (Session& session)
 	: ControlProtocol (session, X_("Wiimote"))
 	, AbstractUI<WiimoteControlUIRequest> ("wiimote")
@@ -114,10 +116,14 @@ WiimoteControlProtocol::stop ()
 {
 	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::stop init\n");
 
-	// release the idle source used for checking for incoming messages
-	g_source_destroy (idle_source);
-	g_source_unref (idle_source);
-	idle_source = 0;
+	// stop wiimote discovery, just in case
+	stop_wiimote_discovery ();
+
+	// close and reset the wiimote handle
+	if (wiimote) {
+		cwiid_close (wiimote);
+		wiimote = 0;
+	}
 
 	// stop the Wiimote control UI
 	BaseUI::quit ();
@@ -141,45 +147,167 @@ WiimoteControlProtocol::thread_init ()
 	PBD::notify_gui_about_thread_creation (X_("gui"), pthread_self (), X_("wiimote"), 2048);
 	SessionEvent::create_per_thread_pool (X_("wiimote"), 128);
 
-	// set up an idle source to check for incoming messages from the Wiimote
+	// connect a Wiimote
+	start_wiimote_discovery ();
+
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::thread_init done\n");
+}
+
+void
+WiimoteControlProtocol::start_wiimote_discovery ()
+{
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::start_wiimote_discovery init\n");
+
+	// connect to the Wiimote using an idle source
 	Glib::RefPtr<Glib::IdleSource> source = Glib::IdleSource::create ();
-	source->connect (sigc::mem_fun (*this, &WiimoteControlProtocol::idle));
+	source->connect (sigc::mem_fun (*this, &WiimoteControlProtocol::connect_idle));
 	source->attach (_main_loop->get_context ());
 
 	// grab a reference on the underlying idle source to keep it around
 	idle_source = source->gobj ();
 	g_source_ref (idle_source);
 
-	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::thread_init done\n");
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::start_wiimote_discovery done\n");
+}
+
+void
+WiimoteControlProtocol::stop_wiimote_discovery ()
+{
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::stop_wiimote_discovery init\n");
+
+	if (idle_source) {
+		g_source_unref (idle_source);
+		idle_source = 0;
+	}
+
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::stop_wiimote_discovery done\n");
+}
+
+bool
+WiimoteControlProtocol::connect_idle ()
+{
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::connect_idle init\n");
+
+	bool retry = true;
+
+	if (connect_wiimote ()) {
+		stop_wiimote_discovery ();
+		retry = false;
+	}
+
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::connect_idle done\n");
+
+	return retry;
 }
 
 bool
-WiimoteControlProtocol::idle ()
+WiimoteControlProtocol::connect_wiimote ()
 {
-	// if the Wiimote is not connected, ask the user to connect it now;
-	// if that fails, try again by calling the idle source again
-	if (!connect_wiimote ()) {
-		sleep (1);
-		return TRUE;
+	// abort the discovery and do nothing else if we already have a Wiimote
+	if (wiimote) {
+		return true;
+	}
+
+	bool success = true;
+
+	// if we don't have a Wiimote yet, try to discover it; if that
+	// fails, wait for a short period of time and try again
+	if (!wiimote) {
+		cerr << "Wiimote: Not discovered yet, press 1+2 to connect" << endl;
+
+		bdaddr_t bdaddr = {{ 0, 0, 0, 0, 0, 0 }};
+		wiimote = cwiid_open (&bdaddr, 0);
+		if (!wiimote) {
+			success = false;
+		} else {
+			// a Wiimote was discovered
+			cerr << "Wiimote: Connected successfully" << endl;
+
+			// attach the WiimoteControlProtocol object to the Wiimote handle
+			if (cwiid_set_data (wiimote, this)) {
+				cerr << "Wiimote: Failed to attach control protocol" << endl;
+				success = false;
+			}
+
+			// clear the last button state to start processing events cleanly
+			button_state = 0;
+		}
+	}
+
+	// enable message based communication with the Wiimote
+	if (success && cwiid_enable (wiimote, CWIID_FLAG_MESG_IFC)) {
+		cerr << "Wiimote: Failed to enable message based communication" << endl;
+		success = false;
+	}
+
+	// enable button events to be received from the Wiimote
+	if (success && cwiid_command (wiimote, CWIID_CMD_RPT_MODE, CWIID_RPT_BTN)) {
+		cerr << "Wiimote: Failed to enable button events" << endl;
+		success = false;
+	}
+
+	// receive an event for every single button pressed, not just when
+	// a different button was pressed than before
+	if (success && cwiid_enable (wiimote, CWIID_FLAG_REPEAT_BTN)) {
+		cerr << "Wiimote: Failed to enable repeated button events" << endl;
+		success = false;
+	}
+
+	// be notified of new input events
+	if (success && cwiid_set_mesg_callback (wiimote, wiimote_control_protocol_mesg_callback)) {
+	}
+
+	// reset Wiimote handle if the configuration failed
+	if (!success && wiimote) {
+		cwiid_close (wiimote);
+		wiimote = 0;
+	}
+
+	return success;
+}
+
+void
+WiimoteControlProtocol::update_led_state ()
+{
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state init\n");
+
+	uint8_t state = 0;
+
+	// do nothing if we do not have a Wiimote
+	if (!wiimote) {
+		DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state no wiimote connected\n");
+		return;
+	}
+
+	// enable LED1 if Ardour is playing
+	if (session->transport_rolling ()) {
+		DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state playing, activate LED1\n");
+		state |= CWIID_LED1_ON;
 	}
 
-	int i;
-	int mesg_count;
-	union cwiid_mesg *mesg;
-	struct timespec timestamp;
+	// enable LED4 if Ardour is recording
+	if (session->actively_recording ()) {
+		DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state recording, activate LED4\n");
+		state |= CWIID_LED4_ON;
+	}
+
+	// apply the LED state
+	cwiid_set_led (wiimote, state);
 
-	cwiid_get_mesg (wiimote, &mesg_count, &mesg, &timestamp);
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state done\n");
+}
 
-	for (i = 0; i < mesg_count; i++) {
-		// reset the Wiimote handle when receiving errors, so that the user
-		// is asked to reconnect it when the idle source is called next time
+void
+WiimoteControlProtocol::wiimote_callback (int mesg_count, union cwiid_mesg mesg[])
+{
+	for (int i = 0; i < mesg_count; i++) {
+		// restart Wiimote discovery when receiving errors
 		if (mesg[i].type == CWIID_MESG_ERROR) {
 			cerr << "Wiimote: disconnected" << endl;
-			if (wiimote) {
-				cwiid_close (wiimote);
-				wiimote = 0;
-			}
-			return TRUE;
+			cwiid_close (wiimote);
+			wiimote = 0;
+			start_wiimote_discovery ();
+			return;
 		}
 
 		// skip non-button events
@@ -285,99 +413,18 @@ WiimoteControlProtocol::idle ()
 			}
 		}
 	}
-
-	return TRUE;
-}
-
-bool
-WiimoteControlProtocol::connect_wiimote ()
-{
-	// do nothing if we already have a Wiimote
-	if (wiimote) {
-		return true;
-	}
-
-	bool success = true;
-
-	// if we don't have a Wiimote yet, try to discover it; if that
-	// fails, wait for a short period of time and try again
-	if (!wiimote) {
-		cerr << "Wiimote: Not discovered yet, press 1+2 to connect" << endl;
-
-		bdaddr_t bdaddr = {{ 0, 0, 0, 0, 0, 0 }};
-		wiimote = cwiid_open (&bdaddr, 0);
-		if (!wiimote) {
-			success = false;
-		} else {
-			// a Wiimote was discovered
-			cerr << "Wiimote: Connected successfully" << endl;
-
-			// attach the WiimoteControlProtocol object to the Wiimote handle
-			if (cwiid_set_data (wiimote, this)) {
-				cerr << "Wiimote: Failed to attach control protocol" << endl;
-				success = false;
-			}
-
-			// clear the last button state to start processing events cleanly
-			button_state = 0;
-		}
-	}
-
-	// enable message based communication with the Wiimote
-	if (success && cwiid_enable (wiimote, CWIID_FLAG_MESG_IFC)) {
-		cerr << "Wiimote: Failed to enable message based communication" << endl;
-		success = false;
-	}
-
-	// enable button events to be received from the Wiimote
-	if (success && cwiid_command (wiimote, CWIID_CMD_RPT_MODE, CWIID_RPT_BTN)) {
-		cerr << "Wiimote: Failed to enable button events" << endl;
-		success = false;
-	}
-
-	// receive an event for every single button pressed, not just when
-	// a different button was pressed than before
-	if (success && cwiid_enable (wiimote, CWIID_FLAG_REPEAT_BTN)) {
-		cerr << "Wiimote: Failed to enable repeated button events" << endl;
-		success = false;
-	}
-
-	// reset Wiimote handle if the configuration failed
-	if (!success && wiimote) {
-		cwiid_close (wiimote);
-		wiimote = 0;
-	}
-
-	return success;
 }
 
 void
-WiimoteControlProtocol::update_led_state ()
+wiimote_control_protocol_mesg_callback (cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg[], timespec *t)
 {
-	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state init\n");
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::mesg_callback init\n");
 
-	uint8_t state = 0;
+	WiimoteControlProtocol *protocol = (WiimoteControlProtocol *)cwiid_get_data (wiimote);
 
-	// do nothing if we do not have a Wiimote
-	if (!wiimote) {
-		DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state no wiimote connected\n");
-		return;
+	if (protocol) {
+		protocol->wiimote_callback (mesg_count, mesg);
 	}
 
-	// enable LED1 if Ardour is playing
-	if (session->transport_rolling ()) {
-		DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state playing, activate LED1\n");
-		state |= CWIID_LED1_ON;
-	}
-
-	// enable LED4 if Ardour is recording
-	if (session->actively_recording ()) {
-		DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state recording, activate LED4\n");
-		state |= CWIID_LED4_ON;
-	}
-
-	// apply the LED state
-	cwiid_set_led (wiimote, state);
-
-	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state done\n");
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::mesg_callback done\n");
 }
diff --git a/libs/surfaces/wiimote/wiimote.h b/libs/surfaces/wiimote/wiimote.h
index 2a2db7a..ec4a683 100644
--- a/libs/surfaces/wiimote/wiimote.h
+++ b/libs/surfaces/wiimote/wiimote.h
@@ -27,7 +27,10 @@ public:
 	XMLNode& get_state ();
 	int set_state (const XMLNode&, int version);
 
-	void wiimote_callback (cwiid_wiimote_t* wiimote, int mesg_count, union cwiid_mesg msg[], struct timespec* t);
+	void start_wiimote_discovery ();
+	void stop_wiimote_discovery ();
+
+	void wiimote_callback (int mesg_count, union cwiid_mesg mesg[]);
 
 protected:
 	void do_request (WiimoteControlUIRequest*);
@@ -36,7 +39,7 @@ protected:
 
 	void thread_init ();
 
-	bool idle ();
+	bool connect_idle ();
 	bool connect_wiimote ();
 
 	void update_led_state ();
-- 
1.7.11.4

jannis

2012-10-02 23:05

reporter   ~0014034

Hi,

I've attached a set of patches to fix compilation of the Wiimote in Ardour 3. The patches should apply fine against the 3.0 branch if processed in the given order. There is more information about the nature of the patches in the patch file headers.

They essential port the Wiimote control surface to BaseUI/AbstractUI and get rid of the thread hackery. The only potential problem I can see is that the member variables of WiimoteControlProtocol are not protected against access from different threads. AFAIK, cwiid uses it's own thread for receiving but I'm not sure in which thread context the message callback is executed. But perhaps I'm complicating things here; I haven't had any problems or crashes with these patches while testing.

Let me know if you spot anything bad or something doesn't work as expected.

nowhiskey

2012-10-03 14:01

reporter   ~0014035

hallo,

first of all - very much thanks that somebody is trying to reimplement this one!

i patched my sources and A3 is building happily with wiimote enabled again.

i see that using the cross, we cannot scroll through the session, but i also found another bug, which is much more worse and makes ardour crash.

steps to reproduce:

1. start jackd in non-rt with a lot of timeout
2. start ardbg
3. create new session
4. connect wiimote by pressing 1+2
5. now press the 'B' button.
6. now press the up-arrow on the cross
7. a window appears, with the following content:


------------
Ardour - : Fatal Error

programming error: no per - thread pool " " for thread 2724035440

Press to exit
--------

the last one is a button, so if i press to exit, ardour will exit.

i ll attach the output of the console, but unfortunately the bt is not created the way i am trying to do it.

cheers,

doc

2012-10-03 14:01

 

ardbg-wii100 (4,631 bytes)   
nowhiskey@murija5:~/Desktop/src/3.0/gtk2_ardour$ ./ardbg
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
<http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from
/home/nowhiskey/Desktop/src/3.0/build/gtk2_ardour/ardour-3.0...done.
(gdb) run
Starting program:
/home/nowhiskey/Desktop/src/3.0/build/gtk2_ardour/ardour-3.0 
[Thread debugging using libthread_db enabled]
Using host libthread_db library
"/lib/i386-linux-gnu/i686/cmov/libthread_db.so.1".
Ardour3.0beta5 (built using ['13201'] and GCC version 4.7.1)
Cannot xinstall SIGPIPE error handler
ardour: [INFO]: Loading default ui configuration file
./../gtk2_ardour/ardour3_ui_default.conf
Loading ui configuration file ./../build/gtk2_ardour/ardour3_ui_dark.rc
ardour: [INFO]: Ardour will be limited to 4096 open files
[New Thread 0xb441eb70 (LWP 6637)]
ardour: [INFO]: Loading system configuration file
./../build/ardour_system.rc
Loading user configuration file /home/nowhiskey/.config/ardour3/ardour.rc
Using SSE optimized routines
[New Thread 0xb3c1db70 (LWP 6638)]
[New Thread 0xb341cb70 (LWP 6639)]
[New Thread 0xb2c1bb70 (LWP 6640)]
[New Thread 0xa8522b70 (LWP 6641)]
[New Thread 0xa7d21b70 (LWP 6642)]
[New Thread 0xa7520b70 (LWP 6643)]
[Thread 0xa7520b70 (LWP 6643) exited]
[Thread 0xa7d21b70 (LWP 6642) exited]
Found 0 along
/home/nowhiskey/.config/ardour3/templates:./../gtk2_ardour/templates:build/gtk2_ardour/templates:./templates
[New Thread 0xa7d21b70 (LWP 6646)]
Failed to expand qname `:symbol'
Attempt to add quad with NULL field.
Failed to expand qname `:symbol'
Attempt to add quad with NULL field.
Failed to expand qname `:symbol'
Attempt to add quad with NULL field.
Failed to expand qname `foaf:name'
Attempt to add quad with NULL field.
Failed to expand qname `foaf:homepage'
Attempt to add quad with NULL field.
Failed to expand qname `foaf:mbox'
Attempt to add quad with NULL field.
Failed to expand qname `foaf:name'
Attempt to add quad with NULL field.
Failed to expand qname `foaf:homepage'
Attempt to add quad with NULL field.
Failed to expand qname `foaf:mbox'
Attempt to add quad with NULL field.
[New Thread 0xa7520b70 (LWP 6650)]
[New Thread 0xa5083c90 (LWP 6651)]
[New Thread 0xa5009b70 (LWP 6652)]
[New Thread 0xa4793b70 (LWP 6653)]
Wiimote: Not discovered yet, press 1+2 to connect
Bluetooth device inquiry error
Wiimote: Not discovered yet, press 1+2 to connect
[Thread 0xa8522b70 (LWP 6641) exited]
[New Thread 0xa8522b70 (LWP 6654)]
Bluetooth device inquiry error
Wiimote: Not discovered yet, press 1+2 to connect
[New Thread 0xa3dffb70 (LWP 6655)]
Bluetooth device inquiry error
Wiimote: Not discovered yet, press 1+2 to connect
[New Thread 0xa35feb70 (LWP 6656)]
Bluetooth device inquiry error
Wiimote: Not discovered yet, press 1+2 to connect
[New Thread 0xa2dfdb70 (LWP 6657)]
Bluetooth device inquiry error
Wiimote: Not discovered yet, press 1+2 to connect
Bluetooth device inquiry error
Wiimote: Not discovered yet, press 1+2 to connect
[Thread 0xa3dffb70 (LWP 6655) exited]
No wiimotes found
Wiimote: Not discovered yet, press 1+2 to connect
No wiimotes found
Wiimote: Not discovered yet, press 1+2 to connect
No wiimotes found
Wiimote: Not discovered yet, press 1+2 to connect
Bluetooth device inquiry error
Wiimote: Not discovered yet, press 1+2 to connect
[Thread 0xa35feb70 (LWP 6656) exited]
No wiimotes found
Wiimote: Not discovered yet, press 1+2 to connect
No wiimotes found
Wiimote: Not discovered yet, press 1+2 to connect
No wiimotes found
Wiimote: Not discovered yet, press 1+2 to connect
[New Thread 0xa35feb70 (LWP 6661)]
[New Thread 0xa3dffb70 (LWP 6662)]
Wiimote: Connected successfully
[New Thread 0xa254cb70 (LWP 6663)]
[Thread 0xa254cb70 (LWP 6663) exited]
[Thread 0xa3dffb70 (LWP 6662) exited]
[Thread 0xa35feb70 (LWP 6661) exited]
[Thread 0xa2dfdb70 (LWP 6657) exited]
[Thread 0xa8522b70 (LWP 6654) exited]
[Thread 0xa4793b70 (LWP 6653) exited]
[Thread 0xa5009b70 (LWP 6652) exited]
[Thread 0xa5083c90 (LWP 6651) exited]
[Thread 0xa7d21b70 (LWP 6646) exited]
[Thread 0xb2c1bb70 (LWP 6640) exited]
[Thread 0xb341cb70 (LWP 6639) exited]
[Thread 0xb3c1db70 (LWP 6638) exited]
[Thread 0xb441eb70 (LWP 6637) exited]
[Thread 0xb44dbad0 (LWP 6633) exited]
[Inferior 1 (process 6633) exited with code 01]
(gdb) thread apply all bt
(gdb) 
ardbg-wii100 (4,631 bytes)   

nowhiskey

2012-10-04 08:43

reporter   ~0014037

hallo,

i realized that my last report is sort of not precisely.

it should be:

5. now press the 'B' button AND KEEP IT PRESSED
6. now press the up-arrow on the cross (while the 'B' button is still pressed too).

cheers,

doc

jannis

2012-10-21 13:37

reporter   ~0014117

@nowhiskey: Sorry it took me so long to respond. I just tried and I can replicate the issue. I'm pretty sure it is independent of how jack is started as it also happens when using realtime etc.

I'll investigate and try to fix it.

nowhiskey

2012-10-21 14:05

reporter   ~0014118

hallo,
very much thanks for looking at this!

i found another 'regression' while running a3 with your patches applied.

-create new session
-->menu->edit->preferences->user interaction
-anable wiimote

if now no bluetooth interface is connected to the machine, the terminal i started ardour from is showing this:

....
No Bluetooth interface found
Wiimote: Not discovered yet, press 1+2 to connect
No Bluetooth interface found
Wiimote: Not discovered yet, press 1+2 to connect
No Bluetooth interface found
.....

while this output is running, a3 becomes somewhat less responsible. it looks, as it would slow down ardours user interface.
once i disable wiimote, the console output stops and UI works faster again.

cheers,

doc

2012-10-21 14:50

 

0007-wiimote-properly-register-the-cwiid-callback-thread-.patch (4,792 bytes)   
From df1a7bcf0fccb075a30d8a74a9014469618204ed Mon Sep 17 00:00:00 2001
From: Jannis Pohlmann <jannis@xfce.org>
Date: Sun, 21 Oct 2012 15:41:50 +0100
Subject: [PATCH 7/7] wiimote: properly register the cwiid callback thread
 with Ardour

This is needed in order to make calls from the cwiid thread to
Ardour via methods like next_marker(), prev_marker(), which would
otherwise result in "programming error: no per-thread pool" errors.
---
 libs/surfaces/wiimote/wiimote.cc | 13 ++++++++++++-
 libs/surfaces/wiimote/wiimote.h  |  1 +
 tools/resample_session.pl        | 16 +++++++++-------
 3 files changed, 22 insertions(+), 8 deletions(-)

diff --git a/libs/surfaces/wiimote/wiimote.cc b/libs/surfaces/wiimote/wiimote.cc
index 879ef67..fc44d2a 100644
--- a/libs/surfaces/wiimote/wiimote.cc
+++ b/libs/surfaces/wiimote/wiimote.cc
@@ -22,6 +22,7 @@ WiimoteControlProtocol::WiimoteControlProtocol (Session& session)
 	, wiimote (0)
 	, idle_source (0)
 	, button_state (0)
+	, callback_thread_registered (false)
 {
 }
 
@@ -123,6 +124,7 @@ WiimoteControlProtocol::stop ()
 	if (wiimote) {
 		cwiid_close (wiimote);
 		wiimote = 0;
+		callback_thread_registered = false;
 	}
 
 	// stop the Wiimote control UI
@@ -145,7 +147,7 @@ WiimoteControlProtocol::thread_init ()
 
 	// allow to make requests to the GUI and RT thread(s)
 	PBD::notify_gui_about_thread_creation (X_("gui"), pthread_self (), X_("wiimote"), 2048);
-	SessionEvent::create_per_thread_pool (X_("wiimote"), 128);
+	BasicUI::register_thread ("wiimote");
 
 	// connect a Wiimote
 	start_wiimote_discovery ();
@@ -217,6 +219,7 @@ WiimoteControlProtocol::connect_wiimote ()
 
 		bdaddr_t bdaddr = {{ 0, 0, 0, 0, 0, 0 }};
 		wiimote = cwiid_open (&bdaddr, 0);
+		callback_thread_registered = false;
 		if (!wiimote) {
 			success = false;
 		} else {
@@ -261,6 +264,7 @@ WiimoteControlProtocol::connect_wiimote ()
 	if (!success && wiimote) {
 		cwiid_close (wiimote);
 		wiimote = 0;
+		callback_thread_registered = false;
 	}
 
 	return success;
@@ -300,12 +304,19 @@ WiimoteControlProtocol::update_led_state ()
 void
 WiimoteControlProtocol::wiimote_callback (int mesg_count, union cwiid_mesg mesg[])
 {
+	// register the cwiid callback thread if that hasn't happened yet
+	if (!callback_thread_registered) {
+		BasicUI::register_thread ("wiimote callback");
+		callback_thread_registered = true;
+	}
+
 	for (int i = 0; i < mesg_count; i++) {
 		// restart Wiimote discovery when receiving errors
 		if (mesg[i].type == CWIID_MESG_ERROR) {
 			cerr << "Wiimote: disconnected" << endl;
 			cwiid_close (wiimote);
 			wiimote = 0;
+			callback_thread_registered = false;
 			start_wiimote_discovery ();
 			return;
 		}
diff --git a/libs/surfaces/wiimote/wiimote.h b/libs/surfaces/wiimote/wiimote.h
index ec4a683..fff168d 100644
--- a/libs/surfaces/wiimote/wiimote.h
+++ b/libs/surfaces/wiimote/wiimote.h
@@ -49,6 +49,7 @@ protected:
 	cwiid_wiimote_t* wiimote;
 	GSource *idle_source;
 	uint16_t button_state;
+	bool callback_thread_registered;
 };
 
 #endif  /* ardour_wiimote_control_protocol_h */
diff --git a/tools/resample_session.pl b/tools/resample_session.pl
index 60bb212..c1f6a79 100755
--- a/tools/resample_session.pl
+++ b/tools/resample_session.pl
@@ -6,7 +6,7 @@
 #
 # Copies the session to another directory and changes it's sampling rate in all respects.
 # The frames in .ardour and .automation files are converted according to the conversion ration.
-# The peakfiles and dead_sounds aren't copied. Only "identified" files are copied, instant.xml's
+# The peakfiles and dead aren't copied. Only "identified" files are copied, instant.xml's
 # or .bak's aren't copied either.
 
 use FindBin '$Bin';
@@ -50,7 +50,7 @@ if ( -d $destDirectory) {
 print "Checking source and destination directories\n";
 
 my @sounds;
-my @dead_sounds;
+my @dead;
 my @dot_ardour;
 my @automation;
 
@@ -80,11 +80,13 @@ if ( -d $sourceDirectory."/sounds/") {
 }
 close(SOUNDS);
 
-# Read the names of all audio files in /dead_sounds/
-opendir(DEAD_SOUNDS,$sourceDirectory."/dead_sounds/") || die ($sourceDirectory.": not a valid session, no dead_sounds/ directory");
+# Read the names of all audio files in /dead/
+opendir(DEAD_SOUNDS,$sourceDirectory."/dead/")
+  || opendir(DEAD_SOUNDS,$sourceDirectory."/dead_sounds/")
+  || die ($sourceDirectory.": not a valid session, no dead/ directory");
 while ( my $file=readdir(DEAD_SOUNDS) ) {
-	if ( -f $sourceDirectory."/dead_sounds/".$file ) {
-		push(@dead_sounds,$file);
+	if ( -f $sourceDirectory."/dead/".$file || -f $sourceDirectory."/dead_sounds/".$file ) {
+		push(@dead,$file);
 	}
 }
 close(DEAD_SOUNDS);
@@ -199,7 +201,7 @@ if ($version_099x eq 1) {
 	}
 }
 
-mkdir $destDirectory."/dead_sounds";
+mkdir $destDirectory."/dead";
 mkdir $destDirectory."/peaks";
 
 
-- 
1.7.11.4

jannis

2012-10-21 14:51

reporter   ~0014119

I found the problem: in my port to Ardour 3, I forgot to register the cwiid callback thread with Ardour. I've uploaded another patch to be applied after the others that fixes this problem. Please test it.

jannis

2012-10-21 14:57

reporter   ~0014120

@nowhiskey:

> while this output is running, a3 becomes somewhat less responsible.
> it looks, as it would slow down ardours user interface.
> once i disable wiimote, the console output stops and UI works faster again.

I know what you mean. I'm not sure this is a regression but I don't have Ardour 2 here to test with. It seems that cwiid_open() blocks the UI even though, from my understanding, the Wiimote code should run in its own thread. I couldn't find a way to avoid this.

BTW, I think the UI is only frozen for a few seconds when you activate the Wiimote plugin. It's not frozen forever, at least not here.

nowhiskey

2012-10-22 13:44

reporter   ~0014125

hallo,
with the last patch applied the crash is gone! thanks for this.

about the regression, when wiimote is not connected, you are right. the ui is freezing just for some seconds. after it, it will work, and if i disable wiimote everything is smooth anyway.

but let's speak about other functions:

pressing left/right on the cross, should scroll through the session.

in the moment, pressing 'B' and any of the crossbuttons (left/right/up/down) as well the '-' or '+' button will set the playhead to the start marker. perhaps it would be possible to make the 'home' button putting the PH at the start and 'B + home' perhaps put the PH at the endmarker.

but that is another story. personally i am missing the function to scroll through the session, since i am using that one very much.

cheers,

doc

jannis

2012-10-22 15:50

reporter   ~0014132

@nowhiskey: The button functions should be the same as before. Left/right should move the playhead back/forward in the session, for instance. +/- should zoom in and out. If you press B plus one of these buttons the behavior is different though.

nowhiskey

2012-10-22 16:08

reporter   ~0014133

ok, i had a better look into it:

left/right does not scrolls the session here. nothing happens when pressing it.

+/- works here too.

the B button:

-when recording, pressing B+A will 'stop recording and delete the captured material'

-B+up/down sets the PH to the next/previous marker

-B+left/right sets the PH to the next/previous region begin/end

-B+ +/- sets the PH to the start/end of the session

-B+home creates a marker at the PH position

-B+1/2 does not do nothing.

so it is all ok here except the scrolling... no idea why, but when pressing left/right nothing is happening here and no information from the console too.

cheers,

doc

jannis

2012-10-22 16:14

reporter   ~0014134

@nowhiskey: Ok, thanks for the information. I'll have a look at left/right when I get home today.

jannis

2012-10-22 19:30

reporter   ~0014137

@nowhiskey: It works fine here. One thing worth noting is that keeping a button pressed does not generate multiple events (so it's not like the keyboard for instance, where keeping 'a' pressed will type 'aaaaaaaa'). It didn't do that in Ardour 2 either. Do left/right work if you press them repeatedly?

nowhiskey

2012-10-23 09:43

reporter   ~0014140

no scrolling here...

there is a test program called 'wmgui' and if i use it on my wiimote, everything seems to be all right here.
i also just tried on a fresh 2.0-ongoing and there the scrolling works smoothly.

cheers,

doc

2013-01-05 00:12

 

0001-wiimote-port-the-wiimote-control-surface-to-Ardour-3.patch (27,415 bytes)   
From e0de8cc37fb3088e1ad6150e0e33aedc94d0ff8a Mon Sep 17 00:00:00 2001
From: Jannis Pohlmann <jannis@xfce.org>
Date: Sat, 8 Sep 2012 11:00:03 +0100
Subject: [PATCH] wiimote: port the wiimote control surface to Ardour 3

Changes include:
* link against cwiid library
* add new PBD::DEBUG::WiimoteControl debug bit
* port to AbstractUI, use IdleSource for receiving messages
* add wiimote surface to ardev_common.sh for debugging
* rework discovery, use callback for receiving input events
---
 gtk2_ardour/ardev_common.sh.in     |   2 +-
 libs/ardour/ardour/debug.h         |   1 +
 libs/ardour/debug.cc               |   1 +
 libs/surfaces/wiimote/interface.cc |  42 +--
 libs/surfaces/wiimote/wiimote.cc   | 551 +++++++++++++++++++++++--------------
 libs/surfaces/wiimote/wiimote.h    |  91 +++---
 libs/surfaces/wiimote/wscript      |   9 +-
 libs/surfaces/wscript              |   2 +
 8 files changed, 410 insertions(+), 289 deletions(-)

diff --git a/gtk2_ardour/ardev_common.sh.in b/gtk2_ardour/ardev_common.sh.in
index 210f282..2a8e23d 100644
--- a/gtk2_ardour/ardev_common.sh.in
+++ b/gtk2_ardour/ardev_common.sh.in
@@ -12,7 +12,7 @@ libs=$TOP/@LIBS@
 
 
 export ARDOUR_PATH=$TOP/gtk2_ardour/icons:$TOP/gtk2_ardour/pixmaps:$TOP/build/gtk2_ardour:$TOP/gtk2_ardour:.
-export ARDOUR_SURFACES_PATH=$libs/surfaces/osc:$libs/surfaces/generic_midi:$libs/surfaces/tranzport:$libs/surfaces/powermate:$libs/surfaces/mackie
+export ARDOUR_SURFACES_PATH=$libs/surfaces/osc:$libs/surfaces/generic_midi:$libs/surfaces/tranzport:$libs/surfaces/powermate:$libs/surfaces/mackie:$libs/surfaces/wiimote
 export ARDOUR_PANNER_PATH=$libs/panners/2in2out:$libs/panners/1in2out:$libs/panners/vbap
 export ARDOUR_DATA_PATH=$TOP/gtk2_ardour:build/gtk2_ardour:.
 export ARDOUR_MIDIMAPS_PATH=$TOP/midi_maps:.
diff --git a/libs/ardour/ardour/debug.h b/libs/ardour/ardour/debug.h
index 334aac5..e97ae79 100644
--- a/libs/ardour/ardour/debug.h
+++ b/libs/ardour/ardour/debug.h
@@ -61,6 +61,7 @@ namespace PBD {
 		extern uint64_t TempoMap;
 		extern uint64_t OrderKeys;
 		extern uint64_t Automation;
+		extern uint64_t WiimoteControl;
 	}
 }
 
diff --git a/libs/ardour/debug.cc b/libs/ardour/debug.cc
index 0d0948d..46da707 100644
--- a/libs/ardour/debug.cc
+++ b/libs/ardour/debug.cc
@@ -58,5 +58,6 @@ uint64_t PBD::DEBUG::TempoMath = PBD::new_debug_bit ("tempomath");
 uint64_t PBD::DEBUG::TempoMap = PBD::new_debug_bit ("tempomap");
 uint64_t PBD::DEBUG::OrderKeys = PBD::new_debug_bit ("orderkeys");
 uint64_t PBD::DEBUG::Automation = PBD::new_debug_bit ("automation");
+uint64_t PBD::DEBUG::WiimoteControl = PBD::new_debug_bit ("wiimotecontrol");
 
 
diff --git a/libs/surfaces/wiimote/interface.cc b/libs/surfaces/wiimote/interface.cc
index 5f622d5..904855f 100644
--- a/libs/surfaces/wiimote/interface.cc
+++ b/libs/surfaces/wiimote/interface.cc
@@ -1,47 +1,25 @@
-#include <pbd/failed_constructor.h>
+#include "pbd/failed_constructor.h"
+#include "pbd/error.h"
 
+#include "ardour/session.h"
 #include "control_protocol/control_protocol.h"
-#include "wiimote.h"
 
-#include "ardour/session.h"
+#include "wiimote.h"
 
 using namespace ARDOUR;
-
-static WiimoteControlProtocol *foo;
+using namespace PBD;
 
 ControlProtocol*
 new_wiimote_protocol (ControlProtocolDescriptor* descriptor, Session* s)
 {
-	WiimoteControlProtocol* wmcp;
-		
-	try {
-		wmcp =  new WiimoteControlProtocol (*s);
-	} catch (failed_constructor& err) {
-		return 0;
-	}
-	
-	if (wmcp-> set_active (true)) {
-		delete wmcp;
-		return 0;
-	}
-
-	foo = wmcp;
-
+	WiimoteControlProtocol* wmcp = new WiimoteControlProtocol (*s);
+	wmcp->set_active (true);
 	return wmcp;
 }
 
 void
-wiimote_control_protocol_cwiid_callback(cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg[], struct timespec *t)
-{
-	assert(foo != 0);
-
-	foo->wiimote_callback(wiimote,mesg_count,mesg,t);
-}
-
-void
 delete_wiimote_protocol (ControlProtocolDescriptor* descriptor, ControlProtocol* cp)
 {
-	foo = 0;
 	delete cp;
 }
 
@@ -62,12 +40,14 @@ static ControlProtocolDescriptor wiimote_descriptor = {
 	initialize : new_wiimote_protocol,
 	destroy : delete_wiimote_protocol
 };
-	
+
 
 extern "C" {
-ControlProtocolDescriptor* 
+
+ControlProtocolDescriptor*
 protocol_descriptor () {
 	return &wiimote_descriptor;
 }
+
 }
 
diff --git a/libs/surfaces/wiimote/wiimote.cc b/libs/surfaces/wiimote/wiimote.cc
index 26f7e18..ed86ad8 100644
--- a/libs/surfaces/wiimote/wiimote.cc
+++ b/libs/surfaces/wiimote/wiimote.cc
@@ -1,291 +1,440 @@
-#include "wiimote.h"
-
 #include <iostream>
-#include <sigc++/bind.h>
 
-#include "pbd/xml++.h"
+#include "pbd/compose.h"
+#include "pbd/error.h"
+#include "ardour/debug.h"
 #include "ardour/session.h"
-
 #include "i18n.h"
 
+#include "wiimote.h"
 
 using namespace ARDOUR;
 using namespace PBD;
+using namespace std;
+
+#include "pbd/abstract_ui.cc" // instantiate template
 
-void wiimote_control_protocol_cwiid_callback(cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg[], struct timespec *t);
+void wiimote_control_protocol_mesg_callback (cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg[], timespec *t);
 
-uint16_t WiimoteControlProtocol::button_state = 0;
+WiimoteControlProtocol::WiimoteControlProtocol (Session& session)
+	: ControlProtocol (session, X_("Wiimote"))
+	, AbstractUI<WiimoteControlUIRequest> ("wiimote")
+	, wiimote (0)
+	, idle_source (0)
+	, button_state (0)
+	, callback_thread_registered (false)
+{
+}
 
-WiimoteControlProtocol::WiimoteControlProtocol ( Session & session) 
-	: ControlProtocol ( session, "Wiimote"),
-	  main_thread_quit (false),
-	  restart_discovery (false),
-	  callback_thread_registered_for_ardour (false),
-	  wiimote_handle (0)
+WiimoteControlProtocol::~WiimoteControlProtocol ()
 {
-	main_thread = Glib::Thread::create( sigc::mem_fun(*this, &WiimoteControlProtocol::wiimote_main), true);
+	stop ();
 }
 
-WiimoteControlProtocol::~WiimoteControlProtocol()
+bool
+WiimoteControlProtocol::probe ()
 {
-	main_thread_quit = true;
-	slot_cond.signal();
-	main_thread->join();
+	return true;
+}
 
-	if (wiimote_handle) {
-		cwiid_close(wiimote_handle);
+int
+WiimoteControlProtocol::set_active (bool yn)
+{
+	int result;
+
+	DEBUG_TRACE (DEBUG::WiimoteControl, string_compose ("WiimoteControlProtocol::set_active init with yn: '%1'\n", yn));
+
+	/* do nothing if the active state is not changing */
+	if (yn == _active) {
+		return 0;
+	}
+
+	if (yn) {
+		/* activate Wiimote control surface */
+		result = start ();
+	} else {
+		/* deactivate Wiimote control surface */
+		result = stop ();
 	}
 
-	std::cerr << "Wiimote: closed" << std::endl;
+	/* remember new active state */
+	_active = yn;
+
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::set_active done\n");
+
+	return result;
 }
 
-bool 
-WiimoteControlProtocol::probe()
+XMLNode&
+WiimoteControlProtocol::get_state ()
 {
-	return true;
+	XMLNode *node = new XMLNode ("Protocol");
+	node->add_property (X_("name"), ARDOUR::ControlProtocol::_name);
+	node->add_property (X_("feedback"), "0");
+	return *node;
+}
+
+int
+WiimoteControlProtocol::set_state (const XMLNode& node, int version)
+{
+	return 0;
 }
 
 void
-WiimoteControlProtocol::wiimote_callback(cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg[], struct timespec *t)
+WiimoteControlProtocol::do_request (WiimoteControlUIRequest* req)
 {
-	int i;
-	uint16_t b;
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::do_request init\n");
 
-	if (!callback_thread_registered_for_ardour) {
-		register_thread("Wiimote Control Protocol");
-		callback_thread_registered_for_ardour = true;
+	if (req->type == CallSlot) {
+		call_slot (MISSING_INVALIDATOR, req->the_slot);
+	} else if (req->type == Quit) {
+		stop ();
 	}
 
-        for (i=0; i < mesg_count; i++)
-	{
-		if (mesg[i].type == CWIID_MESG_ERROR) {	
-			std::cerr << "Wiimote: disconnect" << std::endl;
-			restart_discovery = true;
-			slot_cond.signal();
-			return;
-		}
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::do_request done\n");
+}
 
-		if (mesg[i].type != CWIID_MESG_BTN) continue;
+int
+WiimoteControlProtocol::start ()
+{
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::start init\n");
 
-		// what buttons are pressed down which weren't pressed down last time
-		b = (mesg[i].btn_mesg.buttons ^ button_state) & mesg[i].btn_mesg.buttons;
+	// update LEDs whenever the transport or recording state changes
+	session->TransportStateChange.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&WiimoteControlProtocol::update_led_state, this), this);
+	session->RecordStateChanged.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&WiimoteControlProtocol::update_led_state, this), this);
 
-		button_state = mesg[i].btn_mesg.buttons;
-	
-		// if B is pressed down
-		if (button_state & CWIID_BTN_B) {
-			if (b & CWIID_BTN_A) { // B is down and A is pressed
-				access_action("Transport/ToggleRollForgetCapture");
-			}
+	// start the Wiimote control UI; it will run in its own thread context
+	BaseUI::run ();
 
-			if (b & CWIID_BTN_LEFT) {
-				access_action("Editor/playhead-to-previous-region-boundary");
-			}
-			if (b & CWIID_BTN_RIGHT) {
-				access_action("Editor/playhead-to-next-region-boundary");
-			}
-			if (b & CWIID_BTN_UP) {
-				next_marker();
-			}
-			if (b & CWIID_BTN_DOWN) {
-				prev_marker();
-			}
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::start done\n");
 
-			if (b & CWIID_BTN_HOME) {
-				access_action("Editor/add-location-from-playhead");
-			}
+	return 0;
+}
 
-			if (b & CWIID_BTN_MINUS) {	
-				access_action("Transport/GotoStart");
-			}
-			
-			if (b & CWIID_BTN_PLUS) {
-				access_action("Transport/GotoEnd");
-			}
+int
+WiimoteControlProtocol::stop ()
+{
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::stop init\n");
 
-			continue;
-		}
+	// stop wiimote discovery, just in case
+	stop_wiimote_discovery ();
 
+	// close and reset the wiimote handle
+	if (wiimote) {
+		cwiid_close (wiimote);
+		wiimote = 0;
+		callback_thread_registered = false;
+	}
 
-		if (b & CWIID_BTN_A) {
-			access_action("Transport/ToggleRoll");
-		}
+	// stop the Wiimote control UI
+	BaseUI::quit ();
 
-		if (b & CWIID_BTN_1) { // 1
-			access_action("Editor/track-record-enable-toggle");
-		}
-		if (b & CWIID_BTN_2) { // 2
-			rec_enable_toggle();
-		}
+	// no longer update the LEDs
+	session_connections.drop_connections ();
 
-		// d-pad
-		if (b & CWIID_BTN_LEFT) { // left
-			access_action("Editor/nudge-playhead-backward");
-		}
-		if (b & CWIID_BTN_RIGHT) { // right
-			access_action("Editor/nudge-playhead-forward");
-		}
-		if (b & CWIID_BTN_DOWN) { // down
-			access_action("Editor/select-next-route");
-		}
-		if (b & CWIID_BTN_UP) { // up
-			access_action("Editor/select-prev-route");
-		}
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::stop done\n");
 
+	return 0;
+}
 
-		if (b & CWIID_BTN_PLUS) { // +
-			access_action("Editor/temporal-zoom-in");
-		}
-		if (b & CWIID_BTN_MINUS) { // -
-			access_action("Editor/temporal-zoom-out");
-		}
-		if (b & CWIID_BTN_HOME) { // "home"
-			// no op, yet. any suggestions?
-			access_action("Editor/playhead-to-edit");
-		}
+void
+WiimoteControlProtocol::thread_init ()
+{
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::thread_init init\n");
 
-	}
+	pthread_set_name (X_("wiimote"));
+
+	// allow to make requests to the GUI and RT thread(s)
+	PBD::notify_gui_about_thread_creation (X_("gui"), pthread_self (), X_("wiimote"), 2048);
+	BasicUI::register_thread ("wiimote");
+
+	// connect a Wiimote
+	start_wiimote_discovery ();
+
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::thread_init done\n");
 }
 
 void
-WiimoteControlProtocol::update_led_state()
+WiimoteControlProtocol::start_wiimote_discovery ()
 {
-	ENSURE_WIIMOTE_THREAD(sigc::mem_fun(*this, &WiimoteControlProtocol::update_led_state));
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::start_wiimote_discovery init\n");
 
-	uint8_t state = 0;
+	// connect to the Wiimote using an idle source
+	Glib::RefPtr<Glib::IdleSource> source = Glib::IdleSource::create ();
+	source->connect (sigc::mem_fun (*this, &WiimoteControlProtocol::connect_idle));
+	source->attach (_main_loop->get_context ());
 
-	if (session->transport_rolling()) {
-		state |= CWIID_LED1_ON;
-	}
+	// grab a reference on the underlying idle source to keep it around
+	idle_source = source->gobj ();
+	g_source_ref (idle_source);
 
-	if (session->actively_recording()) {
-		state |= CWIID_LED4_ON;
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::start_wiimote_discovery done\n");
+}
+
+void
+WiimoteControlProtocol::stop_wiimote_discovery ()
+{
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::stop_wiimote_discovery init\n");
+
+	if (idle_source) {
+		g_source_unref (idle_source);
+		idle_source = 0;
 	}
 
-	cwiid_set_led(wiimote_handle, state);
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::stop_wiimote_discovery done\n");
 }
 
-void
-WiimoteControlProtocol::_wiimote_main ()
+bool
+WiimoteControlProtocol::connect_idle ()
 {
-	bdaddr_t bdaddr;
-	unsigned char rpt_mode = 0;
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::connect_idle init\n");
 
-	register_thread ("Wiimote");
+	bool retry = true;
 
-wiimote_discovery:
+	if (connect_wiimote ()) {
+		stop_wiimote_discovery ();
+		retry = false;
+	}
 
-	std::cerr << "Wiimote: discovering, press 1+2" << std::endl;
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::connect_idle done\n");
 
- 	while (!wiimote_handle && !main_thread_quit) {
-		bdaddr = (bdaddr_t) {{0, 0, 0, 0, 0, 0}};
-		callback_thread_registered_for_ardour = false;
-		wiimote_handle = cwiid_open(&bdaddr, 0);
+	return retry;
+}
 
-		if (!wiimote_handle && !main_thread_quit) {
-			sleep(1); 
-			// We don't know whether the issue was a timeout or a configuration 
-			// issue
-		}
+bool
+WiimoteControlProtocol::connect_wiimote ()
+{
+	// abort the discovery and do nothing else if we already have a Wiimote
+	if (wiimote) {
+		return true;
 	}
 
-	if (main_thread_quit) {
-		// The corner case where the wiimote is bound at the same time as
-		// the control protocol is destroyed
-		if (wiimote_handle) {
-			cwiid_close(wiimote_handle);
+	bool success = true;
+
+	// if we don't have a Wiimote yet, try to discover it; if that
+	// fails, wait for a short period of time and try again
+	if (!wiimote) {
+		cerr << "Wiimote: Not discovered yet, press 1+2 to connect" << endl;
+
+		bdaddr_t bdaddr = {{ 0, 0, 0, 0, 0, 0 }};
+		wiimote = cwiid_open (&bdaddr, 0);
+		callback_thread_registered = false;
+		if (!wiimote) {
+			success = false;
+		} else {
+			// a Wiimote was discovered
+			cerr << "Wiimote: Connected successfully" << endl;
+
+			// attach the WiimoteControlProtocol object to the Wiimote handle
+			if (cwiid_set_data (wiimote, this)) {
+				cerr << "Wiimote: Failed to attach control protocol" << endl;
+				success = false;
+			}
+
+			// clear the last button state to start processing events cleanly
+			button_state = 0;
 		}
-		wiimote_handle = 0;
+	}
 
-		std::cerr << "Wiimote Control Protocol stopped before connected to a wiimote" << std::endl;
-		return;
+	// enable message based communication with the Wiimote
+	if (success && cwiid_enable (wiimote, CWIID_FLAG_MESG_IFC)) {
+		cerr << "Wiimote: Failed to enable message based communication" << endl;
+		success = false;
 	}
 
-	std::cerr << "Wiimote: connected" << std::endl;
-	WiimoteControlProtocol::button_state = 0;
+	// enable button events to be received from the Wiimote
+	if (success && cwiid_command (wiimote, CWIID_CMD_RPT_MODE, CWIID_RPT_BTN)) {
+		cerr << "Wiimote: Failed to enable button events" << endl;
+		success = false;
+	}
 
-	if (cwiid_enable(wiimote_handle, CWIID_FLAG_REPEAT_BTN)) {
-		std::cerr << "cwiid_enable(), error" << std::endl;
-		cwiid_close(wiimote_handle);
-		wiimote_handle = 0;
-		return;
+	// receive an event for every single button pressed, not just when
+	// a different button was pressed than before
+	if (success && cwiid_enable (wiimote, CWIID_FLAG_REPEAT_BTN)) {
+		cerr << "Wiimote: Failed to enable repeated button events" << endl;
+		success = false;
 	}
-	if (cwiid_set_mesg_callback(wiimote_handle, wiimote_control_protocol_cwiid_callback)) {
-		std::cerr << "cwiid_set_mesg_callback(), couldn't connect callback" << std::endl;
-		cwiid_close(wiimote_handle);
-		wiimote_handle = 0;
-		return;
-	} 
-	if (cwiid_command(wiimote_handle, CWIID_CMD_RPT_MODE, CWIID_RPT_BTN)) {
-		std::cerr << "cwiid_command(), RPT_MODE error" << std::endl;
-		cwiid_close(wiimote_handle);
-		wiimote_handle = 0;
+
+	// be notified of new input events
+	if (success && cwiid_set_mesg_callback (wiimote, wiimote_control_protocol_mesg_callback)) {
+	}
+
+	// reset Wiimote handle if the configuration failed
+	if (!success && wiimote) {
+		cwiid_close (wiimote);
+		wiimote = 0;
+		callback_thread_registered = false;
+	}
+
+	return success;
+}
+
+void
+WiimoteControlProtocol::update_led_state ()
+{
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state init\n");
+
+	uint8_t state = 0;
+
+	// do nothing if we do not have a Wiimote
+	if (!wiimote) {
+		DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state no wiimote connected\n");
 		return;
 	}
 
-	rpt_mode |= CWIID_RPT_BTN;
-	cwiid_enable(wiimote_handle, CWIID_FLAG_MESG_IFC);
-	cwiid_set_rpt_mode(wiimote_handle, rpt_mode);
+	// enable LED1 if Ardour is playing
+	if (session->transport_rolling ()) {
+		DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state playing, activate LED1\n");
+		state |= CWIID_LED1_ON;
+	}
 
-	transport_state_conn = session->TransportStateChange.connect(sigc::mem_fun(*this, &WiimoteControlProtocol::update_led_state));
-	record_state_conn = session->RecordStateChanged.connect(sigc::mem_fun(*this, &WiimoteControlProtocol::update_led_state));
+	// enable LED4 if Ardour is recording
+	if (session->actively_recording ()) {
+		DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state recording, activate LED4\n");
+		state |= CWIID_LED4_ON;
+	}
 
-	std::cerr << "Wiimote: initialization done, waiting for callbacks / quit" << std::endl;
+	// apply the LED state
+	cwiid_set_led (wiimote, state);
 
-	while (!main_thread_quit) {
-		slot_mutex.lock();
-		while (slot_list.empty() && !main_thread_quit && !restart_discovery)
-			slot_cond.wait(slot_mutex);
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state done\n");
+}
 
-		if (main_thread_quit) {
-			slot_mutex.unlock();
-			break;
+void
+WiimoteControlProtocol::wiimote_callback (int mesg_count, union cwiid_mesg mesg[])
+{
+	// register the cwiid callback thread if that hasn't happened yet
+	if (!callback_thread_registered) {
+		BasicUI::register_thread ("wiimote callback");
+		callback_thread_registered = true;
+	}
+
+	for (int i = 0; i < mesg_count; i++) {
+		// restart Wiimote discovery when receiving errors
+		if (mesg[i].type == CWIID_MESG_ERROR) {
+			cerr << "Wiimote: disconnected" << endl;
+			cwiid_close (wiimote);
+			wiimote = 0;
+			callback_thread_registered = false;
+			start_wiimote_discovery ();
+			return;
 		}
 
-		if (restart_discovery) {
-			std::cerr << "Wiimote: closing wiimote and restarting discovery" << std::endl;
-			if (wiimote_handle) {
-				cwiid_close(wiimote_handle);
-				wiimote_handle = 0;
-			}
-			slot_mutex.unlock();
-			restart_discovery = false;
-			goto wiimote_discovery;
+		// skip non-button events
+		if (mesg[i].type != CWIID_MESG_BTN) {
+			continue;
 		}
 
-		sigc::slot<void> call_me = *slot_list.begin();
-		slot_list.pop_front();
-		slot_mutex.unlock();
+		// drop buttons from the event that were already pressed before
+		uint16_t b = mesg[i].btn_mesg.buttons & ~button_state;
 
-		call_me();
-	}
+		// remember new button state
+		button_state = mesg[i].btn_mesg.buttons;
 
+		if (button_state & CWIID_BTN_B) {
+			// B + A = abort recording and jump back
+			if (b & CWIID_BTN_A) {
+				access_action ("Transport/ToggleRollForgetCapture");
+			}
 
-	std::cerr << "Wiimote: main thread stopped" << std::endl;
-	return 0;
-}
+			// B + left = move playhead to previous region boundary
+			if (b & CWIID_BTN_LEFT) {
+				access_action ("Editor/playhead-to-previous-region-boundary");
+			}
 
+			// B + right = move playhead to next region boundary
+			if (b & CWIID_BTN_RIGHT) {
+				access_action ("Editor/playhead-to-next-region-boundary");
+			}
 
-int
-WiimoteControlProtocol::set_active (bool yn)
-{
-	// Let's not care about this just yet
-	return 0;
+			// B + up = move playhead to next marker
+			if (b & CWIID_BTN_UP) {
+				next_marker ();
+			}
 
-}
+			// B + down = move playhead to prev marker
+			if (b & CWIID_BTN_DOWN) {
+				prev_marker ();
+			}
 
-XMLNode&
-WiimoteControlProtocol::get_state()
-{
-	XMLNode *node = new XMLNode ("Protocol");
-        node->add_property (X_("name"), _name);
-        node->add_property (X_("feedback"), "0");
+			// B + Home = add marker at playhead
+			if (b & CWIID_BTN_HOME) {
+				access_action ("Editor/add-location-from-playhead");
+			}
 
-	return *node;
+			// B + minus = move playhead to the start
+			if (b & CWIID_BTN_MINUS) {
+				access_action ("Transport/GotoStart");
+			}
+
+			// B + plus = move playhead to the end
+			if (b & CWIID_BTN_PLUS) {
+				access_action ("Transport/GotoEnd");
+			}
+		} else {
+			// A = toggle playback
+			if (b & CWIID_BTN_A) {
+				access_action ("Transport/ToggleRoll");
+			}
+
+			// 1 = toggle recording on the current track
+			if (b & CWIID_BTN_1) {
+				access_action ("Editor/track-record-enable-toggle");
+			}
+
+			// 2 = enable recording in general
+			if (b & CWIID_BTN_2) {
+				rec_enable_toggle ();
+			}
+
+			// left = move playhead back a bit
+			if (b & CWIID_BTN_LEFT) {
+				access_action ("Editor/nudge-playhead-backward");
+			}
+
+			// right = move playhead forward a bit
+			if (b & CWIID_BTN_RIGHT) {
+				access_action ("Editor/nudge-playhead-forward");
+			}
+
+			// up = select previous track
+			if (b & CWIID_BTN_UP) {
+				access_action ("Editor/select-prev-route");
+			}
+
+			// down = select next track
+			if (b & CWIID_BTN_DOWN) {
+				access_action ("Editor/select-next-route");
+			}
+
+			// + = zoom in
+			if (b & CWIID_BTN_PLUS) {
+				access_action ("Editor/temporal-zoom-in");
+			}
+
+			// - = zoom out
+			if (b & CWIID_BTN_MINUS) {
+				access_action ("Editor/temporal-zoom-out");
+			}
+
+			// home = no-op
+			if (b & CWIID_BTN_HOME) {
+				access_action ("Editor/playhead-to-edit");
+			}
+		}
+	}
 }
 
-int
-WiimoteControlProtocol::set_state(const XMLNode& node)
+void
+wiimote_control_protocol_mesg_callback (cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg[], timespec *t)
 {
-	return 0;
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::mesg_callback init\n");
+
+	WiimoteControlProtocol *protocol = (WiimoteControlProtocol *)cwiid_get_data (wiimote);
+
+	if (protocol) {
+		protocol->wiimote_callback (mesg_count, mesg);
+	}
+
+	DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::mesg_callback done\n");
 }
diff --git a/libs/surfaces/wiimote/wiimote.h b/libs/surfaces/wiimote/wiimote.h
index 4ab1974..fff168d 100644
--- a/libs/surfaces/wiimote/wiimote.h
+++ b/libs/surfaces/wiimote/wiimote.h
@@ -1,69 +1,56 @@
 #ifndef ardour_wiimote_control_protocol_h
 #define ardour_wiimote_control_protocol_h
 
+#include <cwiid.h>
+
+#include "pbd/abstract_ui.h"
 #include "ardour/types.h"
 #include "control_protocol/control_protocol.h"
 
-#include <glibmm/threads.h>
+struct WiimoteControlUIRequest : public BaseUI::BaseRequestObject {
+public:
+	WiimoteControlUIRequest () {}
+	~WiimoteControlUIRequest () {}
+};
 
-#include "pbd/abstract_ui.h"
+class WiimoteControlProtocol
+	: public ARDOUR::ControlProtocol
+	, public AbstractUI<WiimoteControlUIRequest>
+{
+public:
+	WiimoteControlProtocol (ARDOUR::Session &);
+	virtual ~WiimoteControlProtocol ();
 
-#include <cwiid.h>
+	static bool probe ();
+	int set_active (bool yn);
 
+	XMLNode& get_state ();
+	int set_state (const XMLNode&, int version);
 
-namespace ARDOUR {
-        class Session;
-}
+	void start_wiimote_discovery ();
+	void stop_wiimote_discovery ();
 
-#define ENSURE_WIIMOTE_THREAD(slot) \
-	if (Glib::Threads::Thread::self() != main_thread) {	\
-		slot_mutex.lock();\
-		slot_list.push_back(slot);\
-		slot_cond.signal();\
-		slot_mutex.unlock();\
-		return;\
-	} 
+	void wiimote_callback (int mesg_count, union cwiid_mesg mesg[]);
 
+protected:
+	void do_request (WiimoteControlUIRequest*);
+	int start ();
+	int stop ();
 
-class WiimoteControlProtocol : public ARDOUR::ControlProtocol {
-  public:
-    WiimoteControlProtocol (ARDOUR::Session &);
-    virtual ~WiimoteControlProtocol ();
-    
-    static bool probe();
-    
-    int set_active (bool yn);
-    XMLNode& get_state();
-    int set_state(const XMLNode&);
-    
-    void wiimote_callback(cwiid_wiimote_t *, int, union cwiid_mesg [], 
-			  struct timespec *);
-    
-  private:
-    
-    void wiimote_main();
-    volatile bool main_thread_quit;
-    volatile bool restart_discovery;
-    
-    Glib::Threads::Thread *main_thread;
-    
-    void update_led_state();
-    
-    bool callback_thread_registered_for_ardour;
-    
-    static uint16_t button_state;
-    
-    cwiid_wiimote_t *wiimote_handle;
-    
-    Glib::Threads::Cond slot_cond;
-    Glib::Threads::Mutex slot_mutex;
-    
-    std::list< sigc::slot<void> > slot_list;
-    
-    sigc::connection transport_state_conn;
-    sigc::connection record_state_conn;
-};
+	void thread_init ();
+
+	bool connect_idle ();
+	bool connect_wiimote ();
 
+	void update_led_state ();
+
+protected:
+	PBD::ScopedConnectionList session_connections;
+	cwiid_wiimote_t* wiimote;
+	GSource *idle_source;
+	uint16_t button_state;
+	bool callback_thread_registered;
+};
 
 #endif  /* ardour_wiimote_control_protocol_h */
 
diff --git a/libs/surfaces/wiimote/wscript b/libs/surfaces/wiimote/wscript
index 3fbea7e..3a4bd10 100644
--- a/libs/surfaces/wiimote/wscript
+++ b/libs/surfaces/wiimote/wscript
@@ -26,10 +26,11 @@ def build(bld):
     '''
     obj.export_includes = ['./wiimote']
     obj.cxxflags     = '-DPACKAGE="ardour_wiimote"'
-    obj.includes     = ['.', './wiimote']
-    obj.name         = 'libwiimote'
-    obj.target       = 'wiimote'
-    obj.use          = 'libardour libardour_cp'
+    obj.includes     = ['.', '../libs']
+    obj.name         = 'libardour_wiimote'
+    obj.target       = 'ardour_wiimote'
+    obj.uselib       = 'GTKMM CWIID'
+    obj.use          = 'libardour libardour_cp libgtkmm2ext'
     obj.vnum         = LIBARDOUR_WIIMOTE_LIB_VERSION
     obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3', 'surfaces')
 
diff --git a/libs/surfaces/wscript b/libs/surfaces/wscript
index 5777034..8dfc0d8 100644
--- a/libs/surfaces/wscript
+++ b/libs/surfaces/wscript
@@ -60,6 +60,8 @@ def configure(conf):
         if not conf.is_defined('HAVE_BLUETOOTH_H'):
             print('WIIMOTE configured but you are missing the libbluetooth headers needed to compile wiimote support!')
             sys.exit(1)
+        autowaf.check_pkg(conf, 'cwiid', uselib_store='CWIID',
+                          atleast_version='0.6.00')
         conf.define ('BUILD_WIIMOTE', 1)
 
 def build(bld):
-- 
1.7.11.4

jannis

2013-01-05 00:14

reporter   ~0014428

@paul: I've attached a consolidated single patch now: http://tracker.ardour.org/file_download.php?file_id=2010&type=bug

nowhiskey

2013-01-05 15:17

reporter   ~0014430

hallo,

i did a clean svn co applied the patch and rebuild ardour.
still everything is working here except for left/right scrolling through the session.

cheers,

doc

nowhiskey

2013-01-05 17:11

reporter   ~0014431

one more thing...

i still think it is a regression. it does not happen in A2:

-create session
-enable wiimote
-close the session
-open it again w/out bluetooth being pluged in
-now the terminal shows:

....
No Bluetooth interface found
Wiimote: Not discovered yet, press 1+2 to connect
No Bluetooth interface found
Wiimote: Not discovered yet, press 1+2 to connect
No Bluetooth interface found
.....

and it slows down the opening of the session.

this can be rather confusing esp. to some new users.

sorry for hijacking this one, but for me it looks like nobody else than jannis and me has a wiimote and can try how it works.

cheers,
doc

jannis

2013-01-05 18:32

reporter   ~0014432

@nowhiskey: I can do some debugging again when I'm in the rehearsal room tomorrow. I've not experienced the issues you're seeing. The "no Bluetooth interface found" error sounds odd, almost like that is something outside the surface implementation.

paul

2013-01-07 18:29

administrator   ~0014440

applied as rev 13796

system

2020-04-19 20:15

developer   ~0022310

Issue has been closed automatically, by Trigger Close Plugin.
Feel free to re-open with additional information if you think the issue is not resolved.

Issue History

Date Modified Username Field Change
2010-12-16 21:41 nowhiskey New Issue
2010-12-16 22:04 cth103 cost => 0.00
2010-12-16 22:04 cth103 Target Version => 3.0-beta1
2011-01-29 00:56 paul Note Added: 0009981
2011-02-01 14:20 paul Status new => confirmed
2011-04-23 00:36 cth103 Target Version 3.0-beta1 => 3.X
2012-10-02 23:01 jannis File Added: 0001-wiimote-link-against-cwiid-library.patch
2012-10-02 23:01 jannis File Added: 0002-wiimote-add-new-PBD-DEBUG-WiimoteControl-debug-bit.patch
2012-10-02 23:01 jannis File Added: 0003-wiimote-port-to-AbstractUI-use-IdleSource-for-receiv.patch
2012-10-02 23:01 jannis File Added: 0004-wiimote-update-LEDs-on-transport-recording-state-cha.patch
2012-10-02 23:01 jannis File Added: 0005-wiimote-add-wiimote-surface-to-ardev_common.sh-for-d.patch
2012-10-02 23:02 jannis File Added: 0006-wiimote-rework-discovery-use-callback-for-receiving-.patch
2012-10-02 23:05 jannis Note Added: 0014034
2012-10-03 14:01 nowhiskey Note Added: 0014035
2012-10-03 14:01 nowhiskey File Added: ardbg-wii100
2012-10-04 08:43 nowhiskey Note Added: 0014037
2012-10-21 13:37 jannis Note Added: 0014117
2012-10-21 14:05 nowhiskey Note Added: 0014118
2012-10-21 14:50 jannis File Added: 0007-wiimote-properly-register-the-cwiid-callback-thread-.patch
2012-10-21 14:51 jannis Note Added: 0014119
2012-10-21 14:57 jannis Note Added: 0014120
2012-10-22 13:44 nowhiskey Note Added: 0014125
2012-10-22 15:50 jannis Note Added: 0014132
2012-10-22 16:08 nowhiskey Note Added: 0014133
2012-10-22 16:14 jannis Note Added: 0014134
2012-10-22 19:30 jannis Note Added: 0014137
2012-10-23 09:43 nowhiskey Note Added: 0014140
2013-01-05 00:12 jannis File Added: 0001-wiimote-port-the-wiimote-control-surface-to-Ardour-3.patch
2013-01-05 00:14 jannis Note Added: 0014428
2013-01-05 15:17 nowhiskey Note Added: 0014430
2013-01-05 17:11 nowhiskey Note Added: 0014431
2013-01-05 18:32 jannis Note Added: 0014432
2013-01-07 18:29 paul Note Added: 0014440
2013-01-07 18:29 paul Status confirmed => resolved
2013-01-07 18:29 paul Resolution open => fixed
2013-01-07 18:29 paul Assigned To => paul
2020-04-19 20:15 system Note Added: 0022310
2020-04-19 20:15 system Status resolved => closed