From 02092679808718c993e741f7328a33888ddc294c Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 7 Jan 2013 18:28:09 +0000 Subject: [PATCH] reinstate wiimote support, thanks to work by jannis pohlmann git-svn-id: svn://localhost/ardour2/branches/3.0@13796 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/ardev_common.sh.in | 2 +- libs/ardour/ardour/debug.h | 1 + libs/ardour/debug.cc | 1 + libs/surfaces/wiimote/interface.cc | 68 +-- libs/surfaces/wiimote/wiimote.cc | 675 ++++++++++++++++++----------- libs/surfaces/wiimote/wiimote.h | 123 +++--- libs/surfaces/wiimote/wscript | 9 +- libs/surfaces/wscript | 20 +- wscript | 2 - 9 files changed, 539 insertions(+), 362 deletions(-) diff --git a/gtk2_ardour/ardev_common.sh.in b/gtk2_ardour/ardev_common.sh.in index 40d9a410fa..ff04f60020 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/build:$TOP/gtk2_ardour:$TOP/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 dd76f14603..202d0cc424 100644 --- a/libs/ardour/ardour/debug.h +++ b/libs/ardour/ardour/debug.h @@ -62,6 +62,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 36c9b6adb0..afd5da2169 100644 --- a/libs/ardour/debug.cc +++ b/libs/ardour/debug.cc @@ -59,5 +59,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 5f622d5c09..318bc40adf 100644 --- a/libs/surfaces/wiimote/interface.cc +++ b/libs/surfaces/wiimote/interface.cc @@ -1,52 +1,50 @@ -#include +/* + Copyright (C) 2009-2013 Paul Davis + Authors: Sampo Savolainen, Jannis Pohlmann -#include "control_protocol/control_protocol.h" -#include "wiimote.h" + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "pbd/failed_constructor.h" +#include "pbd/error.h" #include "ardour/session.h" +#include "control_protocol/control_protocol.h" + +#include "wiimote.h" using namespace ARDOUR; - -static WiimoteControlProtocol *foo; +using namespace PBD; ControlProtocol* -new_wiimote_protocol (ControlProtocolDescriptor* descriptor, Session* s) +new_wiimote_protocol (ControlProtocolDescriptor*, 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) +delete_wiimote_protocol (ControlProtocolDescriptor* /*descriptor*/, ControlProtocol* cp) { - 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) +probe_wiimote_protocol (ControlProtocolDescriptor*) { return WiimoteControlProtocol::probe (); } @@ -62,12 +60,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 26f7e1810f..68f2125dcb 100644 --- a/libs/surfaces/wiimote/wiimote.cc +++ b/libs/surfaces/wiimote/wiimote.cc @@ -1,291 +1,460 @@ -#include "wiimote.h" +/* + Copyright (C) 2009-2013 Paul Davis + Authors: Sampo Savolainen, Jannis Pohlmann + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ #include -#include -#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); +#include "pbd/abstract_ui.cc" // instantiate template -uint16_t WiimoteControlProtocol::button_state = 0; +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, "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 ("wiimote") + , wiimote (0) + , idle_source (0) + , button_state (0) + , callback_thread_registered (false) { - 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; + stop (); } -bool -WiimoteControlProtocol::probe() +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"); - -wiimote_discovery: - - std::cerr << "Wiimote: discovering, press 1+2" << std::endl; - - 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); - - 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 call_me = *slot_list.begin(); - slot_list.pop_front(); - slot_mutex.unlock(); - - call_me(); - } - - - std::cerr << "Wiimote: main thread stopped" << std::endl; - return 0; -} - - int WiimoteControlProtocol::set_active (bool yn) { - // Let's not care about this just yet - return 0; + 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 (); + } + + /* remember new active state */ + _active = yn; + + DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::set_active done\n"); + + return result; } XMLNode& -WiimoteControlProtocol::get_state() +WiimoteControlProtocol::get_state () { XMLNode *node = new XMLNode ("Protocol"); - node->add_property (X_("name"), _name); - node->add_property (X_("feedback"), "0"); - + node->add_property (X_("name"), ARDOUR::ControlProtocol::_name); + node->add_property (X_("feedback"), "0"); return *node; } int -WiimoteControlProtocol::set_state(const XMLNode& node) +WiimoteControlProtocol::set_state (const XMLNode&, int) { return 0; } + +void +WiimoteControlProtocol::do_request (WiimoteControlUIRequest* req) +{ + DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::do_request init\n"); + + if (req->type == CallSlot) { + call_slot (MISSING_INVALIDATOR, req->the_slot); + } else if (req->type == Quit) { + stop (); + } + + DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::do_request done\n"); +} + +int +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 (); + + DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::start done\n"); + + return 0; +} + +int +WiimoteControlProtocol::stop () +{ + DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::stop init\n"); + + // 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; + } + + // 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; +} + +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::start_wiimote_discovery () +{ + DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::start_wiimote_discovery init\n"); + + // connect to the Wiimote using an idle source + Glib::RefPtr source = Glib::IdleSource::create (); + 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::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::connect_wiimote () +{ + // 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); + 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; + } + } + + // 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; + 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; + } + + // 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"); +} + +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; + } + + // skip non-button events + if (mesg[i].type != CWIID_MESG_BTN) { + continue; + } + + // drop buttons from the event that were already pressed before + uint16_t b = mesg[i].btn_mesg.buttons & ~button_state; + + // 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"); + } + + // 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"); + } + + // 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 (); + } + + // B + Home = add marker at playhead + if (b & CWIID_BTN_HOME) { + access_action ("Editor/add-location-from-playhead"); + } + + // 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"); + } + } + } +} + +void +wiimote_control_protocol_mesg_callback (cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg[], timespec *) +{ + 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 4ab19749e5..f6ac8edc41 100644 --- a/libs/surfaces/wiimote/wiimote.h +++ b/libs/surfaces/wiimote/wiimote.h @@ -1,69 +1,76 @@ +/* + Copyright (C) 2009-2013 Paul Davis + Authors: Sampo Savolainen, Jannis Pohlmann + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + #ifndef ardour_wiimote_control_protocol_h #define ardour_wiimote_control_protocol_h +#include + +#include "pbd/abstract_ui.h" #include "ardour/types.h" #include "control_protocol/control_protocol.h" -#include - -#include "pbd/abstract_ui.h" - -#include - - -namespace ARDOUR { - class Session; -} - -#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;\ - } - - -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 > slot_list; - - sigc::connection transport_state_conn; - sigc::connection record_state_conn; +struct WiimoteControlUIRequest : public BaseUI::BaseRequestObject { +public: + WiimoteControlUIRequest () {} + ~WiimoteControlUIRequest () {} }; +class WiimoteControlProtocol + : public ARDOUR::ControlProtocol + , public AbstractUI +{ +public: + WiimoteControlProtocol (ARDOUR::Session &); + virtual ~WiimoteControlProtocol (); + + static bool probe (); + int set_active (bool yn); + + XMLNode& get_state (); + int set_state (const XMLNode&, int version); + + void start_wiimote_discovery (); + void stop_wiimote_discovery (); + + void wiimote_callback (int mesg_count, union cwiid_mesg mesg[]); + +protected: + void do_request (WiimoteControlUIRequest*); + int start (); + int stop (); + + 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 3fbea7e248..3a4bd109c2 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 57770340b8..20ad07d60f 100644 --- a/libs/surfaces/wscript +++ b/libs/surfaces/wscript @@ -51,16 +51,16 @@ def configure(conf): conf.check_cc (header_name='linux/input.h', define_name='BUILD_POWERMATE',mandatory=False) autowaf.check_pkg (conf, 'liblo', mandatory=False, uselib_store="LO", atleast_version="0.24") - if Options.options.wiimote: - conf.check_cc (header_name='cwiid.h', define_name='HAVE_CWIID_H') - if not conf.is_defined('HAVE_CWIID_H'): - print('WIIMOTE configured but you are missing libcwiid!') - sys.exit(1) - conf.check_cc (header_name='bluetooth/bluetooth.h', define_name='HAVE_BLUETOOTH_H') - 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) - conf.define ('BUILD_WIIMOTE', 1) + conf.check_cc (header_name='cwiid.h', define_name='HAVE_CWIID_H',mandatory=False) + if conf.is_defined('HAVE_CWIID_H'): + conf.check_cc (header_name='bluetooth/bluetooth.h', define_name='HAVE_BLUETOOTH_H',mandatory=False) + if conf.is_defined('HAVE_BLUETOOTH_H'): + autowaf.check_pkg(conf, 'cwiid', uselib_store='CWIID', atleast_version='0.6.00') + conf.define ('BUILD_WIIMOTE', 1) + else: + print('You are missing the libbluetooth headers needed to compile wiimote support') + else: + print('You are missing the cwiid headers needed to compile wiimote support') def build(bld): bld.recurse('control_protocol') diff --git a/wscript b/wscript index cf90329673..bbf6e140fb 100644 --- a/wscript +++ b/wscript @@ -438,8 +438,6 @@ def options(opt): help='Add revision information to executable name inside the build directory') opt.add_option('--windows-vst', action='store_true', default=False, dest='windows_vst', help='Compile with support for Windows VST') - opt.add_option('--wiimote', action='store_true', default=False, dest='wiimote', - help='Build the wiimote control surface') opt.add_option('--windows-key', type='string', action='store', dest='windows_key', default='Mod4><\'')