2 Copyright (C) 2009-2013 Paul Davis
3 Authors: Sampo Savolainen, Jannis Pohlmann
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "pbd/compose.h"
24 #include "pbd/error.h"
25 #include "ardour/debug.h"
26 #include "ardour/session.h"
31 using namespace ARDOUR;
35 #include "pbd/abstract_ui.cc" // instantiate template
37 void wiimote_control_protocol_mesg_callback (cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg[], timespec *t);
39 WiimoteControlProtocol::WiimoteControlProtocol (Session& session)
40 : ControlProtocol (session, X_("Wiimote"))
41 , AbstractUI<WiimoteControlUIRequest> ("wiimote")
45 , callback_thread_registered (false)
49 WiimoteControlProtocol::~WiimoteControlProtocol ()
55 WiimoteControlProtocol::probe ()
61 WiimoteControlProtocol::set_active (bool yn)
65 DEBUG_TRACE (DEBUG::WiimoteControl, string_compose ("WiimoteControlProtocol::set_active init with yn: '%1'\n", yn));
67 /* do nothing if the active state is not changing */
74 /* activate Wiimote control surface */
77 /* deactivate Wiimote control surface */
81 ControlProtocol::set_active (yn);
83 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::set_active done\n");
89 WiimoteControlProtocol::get_state ()
91 XMLNode& node (ControlProtocol::get_state());
92 node.add_property (X_("feedback"), "0");
97 WiimoteControlProtocol::set_state (const XMLNode&, int)
103 WiimoteControlProtocol::do_request (WiimoteControlUIRequest* req)
105 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::do_request init\n");
107 if (req->type == CallSlot) {
108 call_slot (MISSING_INVALIDATOR, req->the_slot);
109 } else if (req->type == Quit) {
113 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::do_request done\n");
117 WiimoteControlProtocol::start ()
119 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::start init\n");
121 // update LEDs whenever the transport or recording state changes
122 session->TransportStateChange.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&WiimoteControlProtocol::update_led_state, this), this);
123 session->RecordStateChanged.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&WiimoteControlProtocol::update_led_state, this), this);
125 // start the Wiimote control UI; it will run in its own thread context
128 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::start done\n");
134 WiimoteControlProtocol::stop ()
136 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::stop init\n");
138 // stop wiimote discovery, just in case
139 stop_wiimote_discovery ();
141 // close and reset the wiimote handle
143 cwiid_close (wiimote);
145 callback_thread_registered = false;
148 // stop the Wiimote control UI
151 // no longer update the LEDs
152 session_connections.drop_connections ();
154 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::stop done\n");
160 WiimoteControlProtocol::thread_init ()
162 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::thread_init init\n");
164 pthread_set_name (X_("wiimote"));
166 // allow to make requests to the GUI and RT thread(s)
167 PBD::notify_event_loops_about_thread_creation (pthread_self (), X_("wiimote"), 2048);
168 BasicUI::register_thread ("wiimote");
171 start_wiimote_discovery ();
173 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::thread_init done\n");
177 WiimoteControlProtocol::start_wiimote_discovery ()
179 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::start_wiimote_discovery init\n");
181 // connect to the Wiimote using an idle source
182 Glib::RefPtr<Glib::IdleSource> source = Glib::IdleSource::create ();
183 source->connect (sigc::mem_fun (*this, &WiimoteControlProtocol::connect_idle));
184 source->attach (_main_loop->get_context ());
186 // grab a reference on the underlying idle source to keep it around
187 idle_source = source->gobj ();
188 g_source_ref (idle_source);
190 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::start_wiimote_discovery done\n");
194 WiimoteControlProtocol::stop_wiimote_discovery ()
196 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::stop_wiimote_discovery init\n");
199 g_source_unref (idle_source);
203 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::stop_wiimote_discovery done\n");
207 WiimoteControlProtocol::connect_idle ()
209 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::connect_idle init\n");
213 if (connect_wiimote ()) {
214 stop_wiimote_discovery ();
217 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::connect_idle done\n");
223 WiimoteControlProtocol::connect_wiimote ()
225 // abort the discovery and do nothing else if we already have a Wiimote
230 bool success = false;
232 // if we don't have a Wiimote yet, try to discover it; if that
233 // fails, wait for a short period of time and try again
234 for (int i = 0; i < 5; ++i) {
235 cerr << "Wiimote: Not discovered yet, press 1+2 to connect" << endl;
237 bdaddr_t bdaddr = {{ 0, 0, 0, 0, 0, 0 }};
238 wiimote = cwiid_open (&bdaddr, 0);
239 callback_thread_registered = false;
241 // a Wiimote was discovered
242 cerr << "Wiimote: Connected successfully" << endl;
244 // attach the WiimoteControlProtocol object to the Wiimote handle
245 if (cwiid_set_data (wiimote, this)) {
246 cerr << "Wiimote: Failed to attach control protocol" << endl;
249 // clear the last button state to start processing events cleanly
256 // enable message based communication with the Wiimote
257 if (success && cwiid_enable (wiimote, CWIID_FLAG_MESG_IFC)) {
258 cerr << "Wiimote: Failed to enable message based communication" << endl;
262 // enable button events to be received from the Wiimote
263 if (success && cwiid_command (wiimote, CWIID_CMD_RPT_MODE, CWIID_RPT_BTN)) {
264 cerr << "Wiimote: Failed to enable button events" << endl;
268 // receive an event for every single button pressed, not just when
269 // a different button was pressed than before
270 if (success && cwiid_enable (wiimote, CWIID_FLAG_REPEAT_BTN)) {
271 cerr << "Wiimote: Failed to enable repeated button events" << endl;
275 // be notified of new input events
276 if (success && cwiid_set_mesg_callback (wiimote, wiimote_control_protocol_mesg_callback)) {
279 // reset Wiimote handle if the configuration failed
280 if (!success && wiimote) {
281 cwiid_close (wiimote);
283 callback_thread_registered = false;
290 WiimoteControlProtocol::update_led_state ()
292 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state init\n");
296 // do nothing if we do not have a Wiimote
298 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state no wiimote connected\n");
302 // enable LED1 if Ardour is playing
303 if (session->transport_rolling ()) {
304 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state playing, activate LED1\n");
305 state |= CWIID_LED1_ON;
308 // enable LED4 if Ardour is recording
309 if (session->actively_recording ()) {
310 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state recording, activate LED4\n");
311 state |= CWIID_LED4_ON;
314 // apply the LED state
315 cwiid_set_led (wiimote, state);
317 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::update_led_state done\n");
321 WiimoteControlProtocol::wiimote_callback (int mesg_count, union cwiid_mesg mesg[])
323 // register the cwiid callback thread if that hasn't happened yet
324 if (!callback_thread_registered) {
325 BasicUI::register_thread ("wiimote callback");
326 callback_thread_registered = true;
329 for (int i = 0; i < mesg_count; i++) {
330 // restart Wiimote discovery when receiving errors
331 if (mesg[i].type == CWIID_MESG_ERROR) {
332 cerr << "Wiimote: disconnected" << endl;
333 cwiid_close (wiimote);
335 callback_thread_registered = false;
336 start_wiimote_discovery ();
340 // skip non-button events
341 if (mesg[i].type != CWIID_MESG_BTN) {
345 // drop buttons from the event that were already pressed before
346 uint16_t b = mesg[i].btn_mesg.buttons & ~button_state;
348 // remember new button state
349 button_state = mesg[i].btn_mesg.buttons;
351 if (button_state & CWIID_BTN_B) {
352 // B + A = abort recording and jump back
353 if (b & CWIID_BTN_A) {
354 access_action ("Transport/ToggleRollForgetCapture");
357 // B + left = move playhead to previous region boundary
358 if (b & CWIID_BTN_LEFT) {
359 access_action ("Editor/playhead-to-previous-region-boundary");
362 // B + right = move playhead to next region boundary
363 if (b & CWIID_BTN_RIGHT) {
364 access_action ("Editor/playhead-to-next-region-boundary");
367 // B + up = move playhead to next marker
368 if (b & CWIID_BTN_UP) {
372 // B + down = move playhead to prev marker
373 if (b & CWIID_BTN_DOWN) {
377 // B + Home = add marker at playhead
378 if (b & CWIID_BTN_HOME) {
379 access_action ("Editor/add-location-from-playhead");
382 // B + minus = move playhead to the start
383 if (b & CWIID_BTN_MINUS) {
384 access_action ("Transport/GotoStart");
387 // B + plus = move playhead to the end
388 if (b & CWIID_BTN_PLUS) {
389 access_action ("Transport/GotoEnd");
392 // A = toggle playback
393 if (b & CWIID_BTN_A) {
394 access_action ("Transport/ToggleRoll");
397 // 1 = toggle recording on the current track
398 if (b & CWIID_BTN_1) {
399 access_action ("Editor/track-record-enable-toggle");
402 // 2 = enable recording in general
403 if (b & CWIID_BTN_2) {
404 rec_enable_toggle ();
407 // left = move playhead back a bit
408 if (b & CWIID_BTN_LEFT) {
409 access_action ("Editor/nudge-playhead-backward");
412 // right = move playhead forward a bit
413 if (b & CWIID_BTN_RIGHT) {
414 access_action ("Editor/nudge-playhead-forward");
417 // up = select previous track
418 if (b & CWIID_BTN_UP) {
419 access_action ("Editor/select-prev-route");
422 // down = select next track
423 if (b & CWIID_BTN_DOWN) {
424 access_action ("Editor/select-next-route");
428 if (b & CWIID_BTN_PLUS) {
429 access_action ("Editor/temporal-zoom-in");
433 if (b & CWIID_BTN_MINUS) {
434 access_action ("Editor/temporal-zoom-out");
438 if (b & CWIID_BTN_HOME) {
439 access_action ("Editor/playhead-to-edit");
446 wiimote_control_protocol_mesg_callback (cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg[], timespec *)
448 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::mesg_callback init\n");
450 WiimoteControlProtocol *protocol = reinterpret_cast<WiimoteControlProtocol*> (const_cast<void*>(cwiid_get_data (wiimote)));
453 protocol->wiimote_callback (mesg_count, mesg);
456 DEBUG_TRACE (DEBUG::WiimoteControl, "WiimoteControlProtocol::mesg_callback done\n");
461 WiimoteControlProtocol::request_factory (uint32_t num_requests)
463 /* AbstractUI<T>::request_buffer_factory() is a template method only
464 instantiated in this source module. To provide something visible for
465 use in the interface/descriptor, we have this static method that is
468 return request_buffer_factory (num_requests);