summaryrefslogtreecommitdiff
path: root/libs/surfaces
diff options
context:
space:
mode:
Diffstat (limited to 'libs/surfaces')
-rw-r--r--libs/surfaces/control_protocol/basic_ui.cc3
-rw-r--r--libs/surfaces/control_protocol/control_protocol.cc10
-rw-r--r--libs/surfaces/frontier/tranzport/tranzport_control_protocol.cc2
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol.cc91
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol.h11
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol_poll.cc5
-rw-r--r--libs/surfaces/tranzport/init.cc2
-rw-r--r--libs/surfaces/wiimote/SConscript60
-rw-r--r--libs/surfaces/wiimote/interface.cc73
-rw-r--r--libs/surfaces/wiimote/wiimote.cc289
-rw-r--r--libs/surfaces/wiimote/wiimote.h69
11 files changed, 599 insertions, 16 deletions
diff --git a/libs/surfaces/control_protocol/basic_ui.cc b/libs/surfaces/control_protocol/basic_ui.cc
index 71d5794805..b88e002374 100644
--- a/libs/surfaces/control_protocol/basic_ui.cc
+++ b/libs/surfaces/control_protocol/basic_ui.cc
@@ -50,10 +50,9 @@ BasicUI::~BasicUI ()
void
BasicUI::register_thread (std::string name)
{
- PBD::ThreadCreated (pthread_self(), name);
+ PBD::notify_gui_about_thread_creation (pthread_self(), name);
}
-
void
BasicUI::access_action ( std::string action_path )
{
diff --git a/libs/surfaces/control_protocol/control_protocol.cc b/libs/surfaces/control_protocol/control_protocol.cc
index 708373e3bc..1c9ee83833 100644
--- a/libs/surfaces/control_protocol/control_protocol.cc
+++ b/libs/surfaces/control_protocol/control_protocol.cc
@@ -70,14 +70,14 @@ ControlProtocol::next_track (uint32_t initial_id)
id++;
}
- while (id < limit) {
+ while (id <= limit) {
if ((cr = session->route_by_remote_id (id)) != 0) {
break;
}
id++;
}
- if (id == limit) {
+ if (id >= limit) {
id = 0;
while (id != initial_id) {
if ((cr = session->route_by_remote_id (id)) != 0) {
@@ -93,9 +93,9 @@ ControlProtocol::next_track (uint32_t initial_id)
void
ControlProtocol::prev_track (uint32_t initial_id)
{
- uint32_t limit = session->nroutes() - 1;
+ uint32_t limit = session->nroutes();
boost::shared_ptr<Route> cr = route_table[0];
- uint32_t id;
+ int32_t id;
if (cr) {
id = cr->remote_control_id ();
@@ -104,7 +104,7 @@ ControlProtocol::prev_track (uint32_t initial_id)
}
if (id == 0) {
- id = session->nroutes() - 1;
+ id = limit;
} else {
id--;
}
diff --git a/libs/surfaces/frontier/tranzport/tranzport_control_protocol.cc b/libs/surfaces/frontier/tranzport/tranzport_control_protocol.cc
index c874a05de5..5b413273ea 100644
--- a/libs/surfaces/frontier/tranzport/tranzport_control_protocol.cc
+++ b/libs/surfaces/frontier/tranzport/tranzport_control_protocol.cc
@@ -1029,7 +1029,7 @@ TranzportControlProtocol::monitor_work ()
uint8_t offline = 0;
- PBD::ThreadCreated (pthread_self(), X_("Tranzport"));
+ PBD::notify_gui_about_thread_creation (pthread_self(), X_("Tranzport"));
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
next_track ();
diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc
index 502cea581f..f7886e078f 100644
--- a/libs/surfaces/mackie/mackie_control_protocol.cc
+++ b/libs/surfaces/mackie/mackie_control_protocol.cc
@@ -1030,9 +1030,9 @@ void MackieControlProtocol::update_automation( RouteSignal & rs )
}
}
-void MackieControlProtocol::poll_automation()
+void MackieControlProtocol::poll_automation ()
{
- if ( _active )
+ if ( _active && _automation_last.elapsed() >= 20 )
{
// do all currently mapped routes
for( RouteSignals::iterator it = route_signals.begin(); it != route_signals.end(); ++it )
@@ -1041,7 +1041,92 @@ void MackieControlProtocol::poll_automation()
}
// and the master strip
- if ( master_route_signal != 0 ) update_automation( *master_route_signal );
+ if ( master_route_signal != 0 )
+ {
+ update_automation( *master_route_signal );
+ }
+
+ update_timecode_display();
+
+ _automation_last.start();
+ }
+}
+
+string MackieControlProtocol::format_bbt_timecode( nframes_t now_frame )
+{
+ BBT_Time bbt_time;
+ session->bbt_time( now_frame, bbt_time );
+
+ // According to the Logic docs
+ // digits: 888/88/88/888
+ // BBT mode: Bars/Beats/Subdivisions/Ticks
+ ostringstream os;
+ os << setw(3) << setfill('0') << bbt_time.bars;
+ os << setw(2) << setfill('0') << bbt_time.beats;
+
+ // figure out subdivisions per beat
+ const Meter & meter = session->tempo_map().meter_at( now_frame );
+ int subdiv = 2;
+ if ( meter.note_divisor() == 8 && (meter.beats_per_bar() == 12.0 || meter.beats_per_bar() == 9.0 || meter.beats_per_bar() == 6.0) )
+ {
+ subdiv = 3;
+ }
+
+ uint32_t subdivisions = bbt_time.ticks / uint32_t( Meter::ticks_per_beat / subdiv );
+ uint32_t ticks = bbt_time.ticks % uint32_t( Meter::ticks_per_beat / subdiv );
+
+ os << setw(2) << setfill('0') << subdivisions + 1;
+ os << setw(3) << setfill('0') << ticks;
+
+ return os.str();
+}
+
+string MackieControlProtocol::format_smpte_timecode( nframes_t now_frame )
+{
+ SMPTE::Time smpte;
+ session->smpte_time( now_frame, smpte );
+
+ // According to the Logic docs
+ // digits: 888/88/88/888
+ // SMPTE mode: Hours/Minutes/Seconds/Frames
+ ostringstream os;
+ os << setw(3) << setfill('0') << smpte.hours;
+ os << setw(2) << setfill('0') << smpte.minutes;
+ os << setw(2) << setfill('0') << smpte.seconds;
+ os << setw(3) << setfill('0') << smpte.frames;
+
+ return os.str();
+}
+
+void MackieControlProtocol::update_timecode_display()
+{
+ if ( surface().has_timecode_display() )
+ {
+ // do assignment here so current_frame is fixed
+ nframes_t current_frame = session->transport_frame();
+ string timecode;
+
+ switch ( _timecode_type )
+ {
+ case ARDOUR::AnyTime::BBT:
+ timecode = format_bbt_timecode( current_frame );
+ break;
+ case ARDOUR::AnyTime::SMPTE:
+ timecode = format_smpte_timecode( current_frame );
+ break;
+ default:
+ ostringstream os;
+ os << "Unknown timecode: " << _timecode_type;
+ throw runtime_error( os.str() );
+ }
+
+ // only write the timecode string to the MCU if it's changed
+ // since last time. This is to reduce midi bandwidth used.
+ if ( timecode != _timecode_last )
+ {
+ surface().display_timecode( mcu_port(), builder, timecode, _timecode_last );
+ _timecode_last = timecode;
+ }
}
}
diff --git a/libs/surfaces/mackie/mackie_control_protocol.h b/libs/surfaces/mackie/mackie_control_protocol.h
index 0ff7fbd9d4..735a2c88bd 100644
--- a/libs/surfaces/mackie/mackie_control_protocol.h
+++ b/libs/surfaces/mackie/mackie_control_protocol.h
@@ -255,12 +255,19 @@ class MackieControlProtocol
void add_port( MIDI::Port &, int number );
- /// read automation data from the currently active routes and send to surface
- void poll_automation();
+ /**
+ Read session data and send to surface. Includes
+ automation from the currently active routes and
+ timecode displays.
+ */
+ void poll_automation ();
// called from poll_automation to figure out which automations need to be sent
void update_automation( Mackie::RouteSignal & );
+ // also called from poll_automation to update timecode display
+ void update_timecode_display();
+
/**
notification that the port is about to start it's init sequence.
We must make sure that before this exits, the port is being polled
diff --git a/libs/surfaces/mackie/mackie_control_protocol_poll.cc b/libs/surfaces/mackie/mackie_control_protocol_poll.cc
index cf72c35678..cd95551f70 100644
--- a/libs/surfaces/mackie/mackie_control_protocol_poll.cc
+++ b/libs/surfaces/mackie/mackie_control_protocol_poll.cc
@@ -33,8 +33,7 @@ bool MackieControlProtocol::probe()
void * MackieControlProtocol::monitor_work()
{
- // What does ThreadCreatedWithRequestSize do?
- PBD::ThreadCreated (pthread_self(), X_("Mackie"));
+ PBD::notify_gui_about_thread_creation (pthread_self(), X_("Mackie"));
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
@@ -105,6 +104,8 @@ void MackieControlProtocol::read_ports()
for ( int p = 0; p < nfds; ++p )
{
// this will cause handle_midi_any in the MackiePort to be triggered
+ // for alsa/raw ports
+ // alsa/sequencer ports trigger the midi parser off poll
if ( (pfd[p].revents & POLLIN) > 0 )
{
// avoid deadlocking?
diff --git a/libs/surfaces/tranzport/init.cc b/libs/surfaces/tranzport/init.cc
index 94f85bdc56..726cb60d49 100644
--- a/libs/surfaces/tranzport/init.cc
+++ b/libs/surfaces/tranzport/init.cc
@@ -173,7 +173,7 @@ TranzportControlProtocol::monitor_work ()
bool first_time = true;
uint8_t offline = 0;
- PBD::ThreadCreated (pthread_self(), X_("Tranzport"));
+ PBD::notify_gui_about_thread_creation (pthread_self(), X_("Tranzport"));
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
rtpriority_set();
diff --git a/libs/surfaces/wiimote/SConscript b/libs/surfaces/wiimote/SConscript
new file mode 100644
index 0000000000..c530445887
--- /dev/null
+++ b/libs/surfaces/wiimote/SConscript
@@ -0,0 +1,60 @@
+# -*- python -*-
+
+import os
+import os.path
+import glob
+
+Import('env final_prefix install_prefix final_config_prefix libraries i18n')
+
+wiimote = env.Clone()
+
+#
+# this defines the version number of libardour_wiimote
+#
+
+domain = 'ardour_wiimote'
+
+wiimote.Append(DOMAIN = domain, MAJOR = 1, MINOR = 0, MICRO = 0)
+wiimote.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"")
+wiimote.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
+wiimote.Append(PACKAGE = domain)
+wiimote.Append(POTFILE = domain + '.pot')
+
+wiimote_files=Split("""
+wiimote.cc
+interface.cc
+""")
+
+wiimote.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
+wiimote.Append(CXXFLAGS="-DDATA_DIR=\\\""+final_prefix+"/share\\\"")
+wiimote.Append(CXXFLAGS="-DCONFIG_DIR=\\\""+final_config_prefix+"\\\"")
+wiimote.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
+wiimote.Append(LINKFLAGS="-lcwiid")
+#wiimote.Append(CPPPATH = libraries['jack'].get('CPPPATH', []))
+
+wiimote.Merge ([
+ libraries['ardour'],
+ libraries['ardour_cp'],
+ libraries['sndfile'],
+ libraries['midi++2'],
+ libraries['pbd'],
+ libraries['sigc2'],
+ libraries['usb'],
+ libraries['xml'],
+ libraries['glib2'],
+ libraries['glibmm2']
+ ])
+
+libardour_wiimote = wiimote.SharedLibrary('ardour_wiimote', wiimote_files)
+
+if wiimote['WIIMOTE']:
+ Default(libardour_wiimote)
+ env.Alias('install', env.Install(os.path.join(install_prefix, env['LIBDIR'], 'ardour2', 'surfaces'), libardour_wiimote))
+
+if env['NLS']:
+ i18n (wiimote, wiimote_files, env)
+
+env.Alias('tarball', env.Distribute (env['DISTTREE'],
+ [ 'SConscript' ] +
+ wiimote_files +
+ glob.glob('po/*.po') + glob.glob('*.h')))
diff --git a/libs/surfaces/wiimote/interface.cc b/libs/surfaces/wiimote/interface.cc
new file mode 100644
index 0000000000..0ef301dd6c
--- /dev/null
+++ b/libs/surfaces/wiimote/interface.cc
@@ -0,0 +1,73 @@
+#include <pbd/failed_constructor.h>
+
+#include <control_protocol/control_protocol.h>
+#include "wiimote.h"
+
+#include <ardour/session.h>
+
+using namespace ARDOUR;
+
+static WiimoteControlProtocol *foo;
+
+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;
+
+ 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;
+}
+
+bool
+probe_wiimote_protocol (ControlProtocolDescriptor* descriptor)
+{
+ return WiimoteControlProtocol::probe ();
+}
+
+static ControlProtocolDescriptor wiimote_descriptor = {
+ name : "Wiimote",
+ id : "uri://ardour.org/surfaces/wiimote:0",
+ ptr : 0,
+ module : 0,
+ mandatory : 0,
+ supports_feedback : false,
+ probe : probe_wiimote_protocol,
+ initialize : new_wiimote_protocol,
+ destroy : delete_wiimote_protocol
+};
+
+
+extern "C" {
+ControlProtocolDescriptor*
+protocol_descriptor () {
+ return &wiimote_descriptor;
+}
+}
+
diff --git a/libs/surfaces/wiimote/wiimote.cc b/libs/surfaces/wiimote/wiimote.cc
new file mode 100644
index 0000000000..af3bbc369d
--- /dev/null
+++ b/libs/surfaces/wiimote/wiimote.cc
@@ -0,0 +1,289 @@
+#include "wiimote.h"
+
+#include <iostream>
+#include <sigc++/bind.h>
+
+#include <pbd/xml++.h>
+#include <ardour/session.h>
+
+#include "i18n.h"
+
+
+using namespace ARDOUR;
+using namespace PBD;
+
+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;
+
+WiimoteControlProtocol::WiimoteControlProtocol ( Session & session)
+ : ControlProtocol ( session, "Wiimote"),
+ main_thread_quit (false),
+ restart_discovery (false),
+ callback_thread_registered_for_ardour (false),
+ wiimote_handle (0)
+{
+ main_thread = Glib::Thread::create( sigc::mem_fun(*this, &WiimoteControlProtocol::wiimote_main), true);
+}
+
+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;
+}
+
+
+bool
+WiimoteControlProtocol::probe()
+{
+ return true;
+}
+
+void
+WiimoteControlProtocol::wiimote_callback(cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg[], struct timespec *t)
+{
+ int i;
+ uint16_t b;
+
+ if (!callback_thread_registered_for_ardour) {
+ register_thread("Wiimote Control Protocol");
+ callback_thread_registered_for_ardour = true;
+ }
+
+ 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;
+ }
+
+ if (mesg[i].type != CWIID_MESG_BTN) continue;
+
+ // 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;
+
+ 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");
+ }
+
+ 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");
+ }
+
+ if (b & CWIID_BTN_MINUS) {
+ access_action("Transport/GotoStart");
+ }
+
+ if (b & CWIID_BTN_PLUS) {
+ access_action("Transport/GotoEnd");
+ }
+
+ continue;
+ }
+
+
+ if (b & CWIID_BTN_A) {
+ access_action("Transport/ToggleRoll");
+ }
+
+ if (b & CWIID_BTN_1) { // 1
+ access_action("Editor/track-record-enable-toggle");
+ }
+ if (b & CWIID_BTN_2) { // 2
+ rec_enable_toggle();
+ }
+
+ // 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");
+ }
+
+
+ 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::update_led_state()
+{
+ ENSURE_WIIMOTE_THREAD(sigc::mem_fun(*this, &WiimoteControlProtocol::update_led_state));
+
+ uint8_t state = 0;
+
+ if (session->transport_rolling()) {
+ state |= CWIID_LED1_ON;
+ }
+
+ if (session->actively_recording()) {
+ state |= CWIID_LED4_ON;
+ }
+
+ cwiid_set_led(wiimote_handle, state);
+}
+
+void
+WiimoteControlProtocol::wiimote_main()
+{
+ bdaddr_t bdaddr;
+ unsigned char rpt_mode = 0;
+ register_thread("Wiimote Discovery and Callback Thread");
+
+wiimote_discovery:
+
+ std::cerr << "Wiimote: discovering, press 1+2" << std::endl;
+
+ while (!wiimote_handle && !main_thread_quit) {
+ bdaddr = *BDADDR_ANY;
+ callback_thread_registered_for_ardour = false;
+ wiimote_handle = cwiid_open(&bdaddr, 0);
+
+ if (!wiimote_handle && !main_thread_quit) {
+ sleep(1);
+ // We don't know whether the issue was a timeout or a configuration
+ // issue
+ }
+ }
+
+ 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);
+ }
+ wiimote_handle = 0;
+
+ std::cerr << "Wiimote Control Protocol stopped before connected to a wiimote" << std::endl;
+ return;
+ }
+
+ std::cerr << "Wiimote: connected" << std::endl;
+ WiimoteControlProtocol::button_state = 0;
+
+ 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;
+ }
+
+ rpt_mode |= CWIID_RPT_BTN;
+ cwiid_enable(wiimote_handle, CWIID_FLAG_MESG_IFC);
+ cwiid_set_rpt_mode(wiimote_handle, rpt_mode);
+
+ 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));
+
+ std::cerr << "Wiimote: initialization done, waiting for callbacks / quit" << std::endl;
+
+ while (!main_thread_quit) {
+ slot_mutex.lock();
+ while (slot_list.empty() && !main_thread_quit && !restart_discovery)
+ slot_cond.wait(slot_mutex);
+
+ if (main_thread_quit) {
+ slot_mutex.unlock();
+ break;
+ }
+
+ 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;
+ }
+
+ sigc::slot<void> call_me = *slot_list.begin();
+ slot_list.pop_front();
+ slot_mutex.unlock();
+
+ call_me();
+ }
+
+
+ std::cerr << "Wiimote: main thread stopped" << std::endl;
+}
+
+
+int
+WiimoteControlProtocol::set_active (bool yn)
+{
+ // Let's not care about this just yet
+ return 0;
+
+}
+
+XMLNode&
+WiimoteControlProtocol::get_state()
+{
+ XMLNode *node = new XMLNode ("Protocol");
+ node->add_property (X_("name"), _name);
+ node->add_property (X_("feedback"), "0");
+
+ return *node;
+}
+
+int
+WiimoteControlProtocol::set_state(const XMLNode& node)
+{
+ return 0;
+}
diff --git a/libs/surfaces/wiimote/wiimote.h b/libs/surfaces/wiimote/wiimote.h
new file mode 100644
index 0000000000..a6680edd2e
--- /dev/null
+++ b/libs/surfaces/wiimote/wiimote.h
@@ -0,0 +1,69 @@
+#ifndef ardour_wiimote_control_protocol_h
+#define ardour_wiimote_control_protocol_h
+
+#include <ardour/types.h>
+#include <control_protocol/control_protocol.h>
+
+#include <glibmm/thread.h>
+
+#include <pbd/abstract_ui.h>
+
+#include <cwiid.h>
+
+
+namespace ARDOUR {
+ class Session;
+}
+
+#define ENSURE_WIIMOTE_THREAD(slot) \
+ if (Glib::Thread::self() != main_thread) {\
+ slot_mutex.lock();\
+ slot_list.push_back(slot);\
+ slot_cond.signal();\
+ slot_mutex.unlock();\
+ return;\
+ }
+
+
+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::Thread *main_thread;
+
+ void update_led_state();
+
+ bool callback_thread_registered_for_ardour;
+
+ static uint16_t button_state;
+
+ cwiid_wiimote_t *wiimote_handle;
+
+ Glib::Cond slot_cond;
+ Glib::Mutex slot_mutex;
+
+ std::list< sigc::slot<void> > slot_list;
+
+ sigc::connection transport_state_conn;
+ sigc::connection record_state_conn;
+};
+
+
+#endif /* ardour_wiimote_control_protocol_h */
+