diff options
Diffstat (limited to 'libs/surfaces/wiimote/wiimote.cc')
-rw-r--r-- | libs/surfaces/wiimote/wiimote.cc | 289 |
1 files changed, 289 insertions, 0 deletions
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; +} |