various fixes to MidiRegionView selection handling, key handling, drawing of ghost...
[ardour2.git] / libs / surfaces / wiimote / wiimote.cc
blob26f7e1810f58103c4d6461ff60669f0a96127f4a
1 #include "wiimote.h"
3 #include <iostream>
4 #include <sigc++/bind.h>
6 #include "pbd/xml++.h"
7 #include "ardour/session.h"
9 #include "i18n.h"
12 using namespace ARDOUR;
13 using namespace PBD;
15 void wiimote_control_protocol_cwiid_callback(cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg[], struct timespec *t);
17 uint16_t WiimoteControlProtocol::button_state = 0;
19 WiimoteControlProtocol::WiimoteControlProtocol ( Session & session)
20 : ControlProtocol ( session, "Wiimote"),
21 main_thread_quit (false),
22 restart_discovery (false),
23 callback_thread_registered_for_ardour (false),
24 wiimote_handle (0)
26 main_thread = Glib::Thread::create( sigc::mem_fun(*this, &WiimoteControlProtocol::wiimote_main), true);
29 WiimoteControlProtocol::~WiimoteControlProtocol()
31 main_thread_quit = true;
32 slot_cond.signal();
33 main_thread->join();
35 if (wiimote_handle) {
36 cwiid_close(wiimote_handle);
39 std::cerr << "Wiimote: closed" << std::endl;
42 bool
43 WiimoteControlProtocol::probe()
45 return true;
48 void
49 WiimoteControlProtocol::wiimote_callback(cwiid_wiimote_t *wiimote, int mesg_count, union cwiid_mesg mesg[], struct timespec *t)
51 int i;
52 uint16_t b;
54 if (!callback_thread_registered_for_ardour) {
55 register_thread("Wiimote Control Protocol");
56 callback_thread_registered_for_ardour = true;
59 for (i=0; i < mesg_count; i++)
61 if (mesg[i].type == CWIID_MESG_ERROR) {
62 std::cerr << "Wiimote: disconnect" << std::endl;
63 restart_discovery = true;
64 slot_cond.signal();
65 return;
68 if (mesg[i].type != CWIID_MESG_BTN) continue;
70 // what buttons are pressed down which weren't pressed down last time
71 b = (mesg[i].btn_mesg.buttons ^ button_state) & mesg[i].btn_mesg.buttons;
73 button_state = mesg[i].btn_mesg.buttons;
75 // if B is pressed down
76 if (button_state & CWIID_BTN_B) {
77 if (b & CWIID_BTN_A) { // B is down and A is pressed
78 access_action("Transport/ToggleRollForgetCapture");
81 if (b & CWIID_BTN_LEFT) {
82 access_action("Editor/playhead-to-previous-region-boundary");
84 if (b & CWIID_BTN_RIGHT) {
85 access_action("Editor/playhead-to-next-region-boundary");
87 if (b & CWIID_BTN_UP) {
88 next_marker();
90 if (b & CWIID_BTN_DOWN) {
91 prev_marker();
94 if (b & CWIID_BTN_HOME) {
95 access_action("Editor/add-location-from-playhead");
98 if (b & CWIID_BTN_MINUS) {
99 access_action("Transport/GotoStart");
102 if (b & CWIID_BTN_PLUS) {
103 access_action("Transport/GotoEnd");
106 continue;
110 if (b & CWIID_BTN_A) {
111 access_action("Transport/ToggleRoll");
114 if (b & CWIID_BTN_1) { // 1
115 access_action("Editor/track-record-enable-toggle");
117 if (b & CWIID_BTN_2) { // 2
118 rec_enable_toggle();
121 // d-pad
122 if (b & CWIID_BTN_LEFT) { // left
123 access_action("Editor/nudge-playhead-backward");
125 if (b & CWIID_BTN_RIGHT) { // right
126 access_action("Editor/nudge-playhead-forward");
128 if (b & CWIID_BTN_DOWN) { // down
129 access_action("Editor/select-next-route");
131 if (b & CWIID_BTN_UP) { // up
132 access_action("Editor/select-prev-route");
136 if (b & CWIID_BTN_PLUS) { // +
137 access_action("Editor/temporal-zoom-in");
139 if (b & CWIID_BTN_MINUS) { // -
140 access_action("Editor/temporal-zoom-out");
142 if (b & CWIID_BTN_HOME) { // "home"
143 // no op, yet. any suggestions?
144 access_action("Editor/playhead-to-edit");
150 void
151 WiimoteControlProtocol::update_led_state()
153 ENSURE_WIIMOTE_THREAD(sigc::mem_fun(*this, &WiimoteControlProtocol::update_led_state));
155 uint8_t state = 0;
157 if (session->transport_rolling()) {
158 state |= CWIID_LED1_ON;
161 if (session->actively_recording()) {
162 state |= CWIID_LED4_ON;
165 cwiid_set_led(wiimote_handle, state);
168 void
169 WiimoteControlProtocol::_wiimote_main ()
171 bdaddr_t bdaddr;
172 unsigned char rpt_mode = 0;
174 register_thread ("Wiimote");
176 wiimote_discovery:
178 std::cerr << "Wiimote: discovering, press 1+2" << std::endl;
180 while (!wiimote_handle && !main_thread_quit) {
181 bdaddr = (bdaddr_t) {{0, 0, 0, 0, 0, 0}};
182 callback_thread_registered_for_ardour = false;
183 wiimote_handle = cwiid_open(&bdaddr, 0);
185 if (!wiimote_handle && !main_thread_quit) {
186 sleep(1);
187 // We don't know whether the issue was a timeout or a configuration
188 // issue
192 if (main_thread_quit) {
193 // The corner case where the wiimote is bound at the same time as
194 // the control protocol is destroyed
195 if (wiimote_handle) {
196 cwiid_close(wiimote_handle);
198 wiimote_handle = 0;
200 std::cerr << "Wiimote Control Protocol stopped before connected to a wiimote" << std::endl;
201 return;
204 std::cerr << "Wiimote: connected" << std::endl;
205 WiimoteControlProtocol::button_state = 0;
207 if (cwiid_enable(wiimote_handle, CWIID_FLAG_REPEAT_BTN)) {
208 std::cerr << "cwiid_enable(), error" << std::endl;
209 cwiid_close(wiimote_handle);
210 wiimote_handle = 0;
211 return;
213 if (cwiid_set_mesg_callback(wiimote_handle, wiimote_control_protocol_cwiid_callback)) {
214 std::cerr << "cwiid_set_mesg_callback(), couldn't connect callback" << std::endl;
215 cwiid_close(wiimote_handle);
216 wiimote_handle = 0;
217 return;
219 if (cwiid_command(wiimote_handle, CWIID_CMD_RPT_MODE, CWIID_RPT_BTN)) {
220 std::cerr << "cwiid_command(), RPT_MODE error" << std::endl;
221 cwiid_close(wiimote_handle);
222 wiimote_handle = 0;
223 return;
226 rpt_mode |= CWIID_RPT_BTN;
227 cwiid_enable(wiimote_handle, CWIID_FLAG_MESG_IFC);
228 cwiid_set_rpt_mode(wiimote_handle, rpt_mode);
230 transport_state_conn = session->TransportStateChange.connect(sigc::mem_fun(*this, &WiimoteControlProtocol::update_led_state));
231 record_state_conn = session->RecordStateChanged.connect(sigc::mem_fun(*this, &WiimoteControlProtocol::update_led_state));
233 std::cerr << "Wiimote: initialization done, waiting for callbacks / quit" << std::endl;
235 while (!main_thread_quit) {
236 slot_mutex.lock();
237 while (slot_list.empty() && !main_thread_quit && !restart_discovery)
238 slot_cond.wait(slot_mutex);
240 if (main_thread_quit) {
241 slot_mutex.unlock();
242 break;
245 if (restart_discovery) {
246 std::cerr << "Wiimote: closing wiimote and restarting discovery" << std::endl;
247 if (wiimote_handle) {
248 cwiid_close(wiimote_handle);
249 wiimote_handle = 0;
251 slot_mutex.unlock();
252 restart_discovery = false;
253 goto wiimote_discovery;
256 sigc::slot<void> call_me = *slot_list.begin();
257 slot_list.pop_front();
258 slot_mutex.unlock();
260 call_me();
264 std::cerr << "Wiimote: main thread stopped" << std::endl;
265 return 0;
270 WiimoteControlProtocol::set_active (bool yn)
272 // Let's not care about this just yet
273 return 0;
277 XMLNode&
278 WiimoteControlProtocol::get_state()
280 XMLNode *node = new XMLNode ("Protocol");
281 node->add_property (X_("name"), _name);
282 node->add_property (X_("feedback"), "0");
284 return *node;
288 WiimoteControlProtocol::set_state(const XMLNode& node)
290 return 0;