2 * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
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)
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.
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.
26 #include "pbd/compose.h"
27 #include "pbd/error.h"
29 #include "pbd/abstract_ui.cc" // instantiate template
31 #include "ardour/async_midi_port.h"
32 #include "ardour/audioengine.h"
33 #include "ardour/session.h"
35 #include "midi++/port.h"
37 #include "maschine2.h"
39 #include "m2_dev_mk2.h"
40 #include "m2_map_mk2.h"
42 #include "m2_dev_mikro.h"
43 #include "m2_map_mikro.h"
47 using namespace ARDOUR;
49 using namespace ArdourSurface;
51 Maschine2::Maschine2 (ARDOUR::Session& s)
52 : ControlProtocol (s, string (X_("NI Maschine2")))
53 , AbstractUI<Maschine2Request> (name())
58 , _maschine_type (Maschine)
59 , _master_state (MST_NONE)
62 throw Maschine2Exception ("HIDAPI initialization failed");
67 Maschine2::~Maschine2 ()
74 Maschine2::request_factory (uint32_t num_requests)
76 return request_buffer_factory (num_requests);
80 Maschine2::do_request (Maschine2Request* req)
82 if (req->type == CallSlot) {
83 call_slot (MISSING_INVALIDATOR, req->the_slot);
84 } else if (req->type == Quit) {
90 Maschine2::set_active (bool yn)
106 ControlProtocol::set_active (yn);
111 Maschine2::get_state()
113 XMLNode& node (ControlProtocol::get_state());
118 Maschine2::set_state (const XMLNode & node, int version)
120 if (ControlProtocol::set_state (node, version)) {
129 _maschine_type = Maschine;
130 _handle = hid_open (0x17cc, 0x1140, NULL); // Maschine
134 if ((_handle = hid_open (0x17cc, 0x1300, NULL))) {
135 _maschine_type = Studio;
141 if ((_handle = hid_open (0x17cc, 0x1110, NULL))) {
142 _maschine_type = Mikro;
146 if ((_handle = hid_open (0x17cc, 0x1200, NULL))) {
147 _maschine_type = Mikro;
152 error << _("Cannot find or connect to Maschine2\n");
156 hid_set_nonblocking (_handle, 1);
158 _midi_out = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("Maschine2 out"), true);
160 error << _("Cannot create Maschine2 PAD MIDI Port");
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();
168 switch (_maschine_type) {
170 _hw = new Maschine2Mikro ();
171 _ctrl = new M2MapMikro ();
172 info << _("Maschine2 Mikro control surface intialized");
175 _hw = new Maschine2Mk2 ();
176 _ctrl = new M2MapMk2 ();
177 info << _("Maschine2 control surface intialized");
180 error << _("Maschine2 Studio is not yet supported");
186 _canvas = new Maschine2Canvas (*this, _hw);
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());
193 #ifdef PLATFORM_WINDOWS
194 Glib::RefPtr<Glib::TimeoutSource> read_timeout = Glib::TimeoutSource::create (20);
196 Glib::RefPtr<Glib::TimeoutSource> read_timeout = Glib::TimeoutSource::create (1);
198 read_connection = read_timeout->connect (sigc::mem_fun (*this, &Maschine2::dev_read));
199 read_timeout->attach (main_loop ()->get_context());
207 read_connection.disconnect ();
208 write_connection.disconnect ();
210 session_connections.drop_connections ();
211 button_connections.drop_connections ();
213 if (_handle && _hw) {
215 _hw->write (_handle, NULL);
224 AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*> (_output_port);
225 asp->drain (10000, 500000);
227 AudioEngine::instance()->unregister_port (_midi_out);
228 _midi_out.reset ((ARDOUR::Port*) 0);
243 Maschine2::thread_init ()
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);
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.
258 Maschine2::run_event_loop ()
264 Maschine2::stop_event_loop ()
270 Maschine2::dev_read ()
272 _hw->read (_handle, _ctrl);
277 Maschine2::dev_write ()
279 _hw->write (_handle, _ctrl);
283 // move to callbacks.c || M2Contols implementation
285 Maschine2::current_layout() const