Skeleton for NI Maschine2 Surface
[ardour.git] / libs / surfaces / maschine2 / maschine2.cc
1 /*
2  * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2, or (at your option)
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdint.h>
23 #include <unistd.h>
24 #include <pthread.h>
25
26 #include "pbd/compose.h"
27 #include "pbd/error.h"
28 #include "pbd/i18n.h"
29 #include "pbd/abstract_ui.cc" // instantiate template
30
31 #include "ardour/async_midi_port.h"
32 #include "ardour/audioengine.h"
33 #include "ardour/session.h"
34
35 #include "midi++/port.h"
36
37 #include "maschine2.h"
38
39 #include "m2_dev_mk2.h"
40 #include "m2_map_mk2.h"
41
42 #include "m2_dev_mikro.h"
43 #include "m2_map_mikro.h"
44
45 #include "canvas.h"
46
47 using namespace ARDOUR;
48 using namespace PBD;
49 using namespace ArdourSurface;
50
51 Maschine2::Maschine2 (ARDOUR::Session& s)
52         : ControlProtocol (s, string (X_("NI Maschine2")))
53         , AbstractUI<Maschine2Request> (name())
54         , _handle (0)
55         , _hw (0)
56         , _ctrl (0)
57         , _canvas (0)
58         , _maschine_type (Maschine)
59         , _master_state (MST_NONE)
60 {
61         if (hid_init()) {
62                 throw Maschine2Exception ("HIDAPI initialization failed");
63         }
64         run_event_loop ();
65 }
66
67 Maschine2::~Maschine2 ()
68 {
69         stop ();
70         hid_exit ();
71 }
72
73 void*
74 Maschine2::request_factory (uint32_t num_requests)
75 {
76         return request_buffer_factory (num_requests);
77 }
78
79 void
80 Maschine2::do_request (Maschine2Request* req)
81 {
82         if (req->type == CallSlot) {
83                 call_slot (MISSING_INVALIDATOR, req->the_slot);
84         } else if (req->type == Quit) {
85                 stop ();
86         }
87 }
88
89 int
90 Maschine2::set_active (bool yn)
91 {
92         if (yn == active()) {
93                 return 0;
94         }
95
96         if (yn) {
97                 if (start ()) {
98                         return -1;
99                 }
100         } else {
101                 if (stop ()) {
102                         return -1;
103                 }
104         }
105
106         ControlProtocol::set_active (yn);
107         return 0;
108 }
109
110 XMLNode&
111 Maschine2::get_state()
112 {
113         XMLNode& node (ControlProtocol::get_state());
114         return node;
115 }
116
117 int
118 Maschine2::set_state (const XMLNode & node, int version)
119 {
120         if (ControlProtocol::set_state (node, version)) {
121                 return -1;
122         }
123         return 0;
124 }
125
126 int
127 Maschine2::start ()
128 {
129         _maschine_type = Maschine;
130         _handle = hid_open (0x17cc, 0x1140, NULL); // Maschine
131
132 #if 0
133         if (!_handle) {
134                 if ((_handle = hid_open (0x17cc, 0x1300, NULL))) {
135                         _maschine_type = Studio;
136                 }
137         }
138 #endif
139
140         if (!_handle) {
141                 if ((_handle = hid_open (0x17cc, 0x1110, NULL))) {
142                         _maschine_type = Mikro;
143                 }
144         }
145         if (!_handle) {
146                 if ((_handle = hid_open (0x17cc, 0x1200, NULL))) {
147                         _maschine_type = Mikro;
148                 }
149         }
150
151         if (!_handle) {
152                 error << _("Cannot find or connect to Maschine2\n");
153                 return -1;
154         }
155
156         hid_set_nonblocking (_handle, 1);
157
158         _midi_out = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("Maschine2 out"), true);
159         if (!_midi_out) {
160                 error << _("Cannot create Maschine2 PAD MIDI Port");
161                 stop ();
162                 return -1;
163         }
164
165         boost::dynamic_pointer_cast<AsyncMIDIPort>(_midi_out)->set_flush_at_cycle_start (true);
166         _output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_midi_out).get();
167
168         switch (_maschine_type) {
169                 case Mikro:
170                         _hw = new Maschine2Mikro ();
171                         _ctrl = new M2MapMikro ();
172                         info << _("Maschine2 Mikro control surface intialized");
173                         break;
174                 case Maschine:
175                         _hw = new Maschine2Mk2 ();
176                         _ctrl = new M2MapMk2 ();
177                         info << _("Maschine2 control surface intialized");
178                         break;
179                 case Studio:
180                         error << _("Maschine2 Studio is not yet supported");
181                         stop ();
182                         return -1;
183                         break;
184         }
185
186         _canvas = new Maschine2Canvas (*this, _hw);
187         connect_signals ();
188
189         Glib::RefPtr<Glib::TimeoutSource> write_timeout = Glib::TimeoutSource::create (40);
190         write_connection = write_timeout->connect (sigc::mem_fun (*this, &Maschine2::dev_write));
191         write_timeout->attach (main_loop()->get_context());
192
193 #ifdef PLATFORM_WINDOWS
194         Glib::RefPtr<Glib::TimeoutSource> read_timeout = Glib::TimeoutSource::create (20);
195 #else
196         Glib::RefPtr<Glib::TimeoutSource> read_timeout = Glib::TimeoutSource::create (1);
197 #endif
198         read_connection = read_timeout->connect (sigc::mem_fun (*this, &Maschine2::dev_read));
199         read_timeout->attach (main_loop ()->get_context());
200
201         return 0;
202 }
203
204 int
205 Maschine2::stop ()
206 {
207         read_connection.disconnect ();
208         write_connection.disconnect ();
209
210         session_connections.drop_connections ();
211         button_connections.drop_connections ();
212
213         if (_handle && _hw) {
214                 _hw->clear ();
215                 _hw->write (_handle, NULL);
216         }
217
218         hid_close (_handle);
219         _handle = 0;
220
221         stop_event_loop ();
222
223         if (_midi_out) {
224                 AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*> (_output_port);
225                 asp->drain (10000, 500000);
226
227                 AudioEngine::instance()->unregister_port (_midi_out);
228                 _midi_out.reset ((ARDOUR::Port*) 0);
229                 _output_port = 0;
230         }
231
232         delete _canvas;
233         delete _hw;
234         delete _ctrl;
235
236         _canvas = 0;
237         _hw = 0;
238         _ctrl = 0;
239         return 0;
240 }
241
242 void
243 Maschine2::thread_init ()
244 {
245         pthread_set_name (event_loop_name().c_str());
246         ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 1024);
247         PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 1024);
248
249         struct sched_param rtparam;
250         memset (&rtparam, 0, sizeof (rtparam));
251         rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
252         if (pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam) != 0) {
253                 // do we care? not particularly.
254         }
255 }
256
257 void
258 Maschine2::run_event_loop ()
259 {
260         BaseUI::run ();
261 }
262
263 void
264 Maschine2::stop_event_loop ()
265 {
266         BaseUI::quit ();
267 }
268
269 bool
270 Maschine2::dev_read ()
271 {
272         _hw->read (_handle, _ctrl);
273         return true;
274 }
275
276 bool
277 Maschine2::dev_write ()
278 {
279         _hw->write (_handle, _ctrl);
280         return true;
281 }
282
283 // move to callbacks.c || M2Contols implementation
284 Maschine2Layout*
285 Maschine2::current_layout() const
286 {
287         return NULL;
288 }