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;
52 #include "gtkmm2ext/colors.h"
53 #include "canvas/line.h"
54 #include "canvas/rectangle.h"
55 #include "canvas/text.h"
61 class TestLayout : public Maschine2Layout
64 TestLayout (Maschine2& m2, Session& s, std::string const & name)
65 : Maschine2Layout (m2, s, name)
69 using namespace ArdourCanvas;
70 bg = new ArdourCanvas::Rectangle (this);
71 bg->set (ArdourCanvas::Rect (0, 0, display_width(), display_height()));
72 bg->set_fill_color (0x000000ff);
74 upper_line = new Line (this);
75 upper_line->set (Duple (0, 16.5), Duple (display_width(), 16.5));
76 upper_line->set_outline_color (0xffffffff);
78 knob = new Maschine2Knob(&m2, this);
79 knob->set_position (Duple (64 + 32, 32));
80 if (_session.master_out ()) {
81 knob->set_controllable (_session.master_out ()->gain_control());
84 std::vector<std::string> strs;
85 strs.push_back("T|sg1");
86 strs.push_back("Test2asdjasdlkjasldkjasd");
87 strs.push_back("Test3");
88 strs.push_back("Test4");
89 strs.push_back("Test5");
90 menu = new Maschine2Menu(&m2, this, strs);
91 menu->set_position (Duple (0, 19));
94 Maschine2Knob* get_knob () { return knob; }
95 Maschine2Menu* get_menu () { return menu; }
97 ArdourCanvas::Rectangle* bg;
98 ArdourCanvas::Line* upper_line;
103 static TestLayout* tl = NULL;
106 Maschine2::Maschine2 (ARDOUR::Session& s)
107 : ControlProtocol (s, string (X_("NI Maschine2")))
108 , AbstractUI<Maschine2Request> (name())
113 , _maschine_type (Maschine)
114 , _master_state (MST_NONE)
117 throw Maschine2Exception ("HIDAPI initialization failed");
122 Maschine2::~Maschine2 ()
129 Maschine2::request_factory (uint32_t num_requests)
131 return request_buffer_factory (num_requests);
135 Maschine2::do_request (Maschine2Request* req)
137 if (req->type == CallSlot) {
138 call_slot (MISSING_INVALIDATOR, req->the_slot);
139 } else if (req->type == Quit) {
145 Maschine2::set_active (bool yn)
147 if (yn == active()) {
161 ControlProtocol::set_active (yn);
166 Maschine2::get_state()
168 XMLNode& node (ControlProtocol::get_state());
173 Maschine2::set_state (const XMLNode & node, int version)
175 if (ControlProtocol::set_state (node, version)) {
184 _maschine_type = Maschine;
185 _handle = hid_open (0x17cc, 0x1140, NULL); // Maschine
189 if ((_handle = hid_open (0x17cc, 0x1300, NULL))) {
190 _maschine_type = Studio;
196 if ((_handle = hid_open (0x17cc, 0x1110, NULL))) {
197 _maschine_type = Mikro;
201 if ((_handle = hid_open (0x17cc, 0x1200, NULL))) {
202 _maschine_type = Mikro;
207 error << _("Cannot find or connect to Maschine2\n");
211 hid_set_nonblocking (_handle, 1);
213 _midi_out = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("Maschine2 out"), true);
215 error << _("Cannot create Maschine2 PAD MIDI Port");
220 boost::dynamic_pointer_cast<AsyncMIDIPort>(_midi_out)->set_flush_at_cycle_start (true);
221 _output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_midi_out).get();
223 switch (_maschine_type) {
225 _hw = new Maschine2Mikro ();
226 _ctrl = new M2MapMikro ();
227 info << _("Maschine2 Mikro control surface intialized");
230 _hw = new Maschine2Mk2 ();
231 _ctrl = new M2MapMk2 ();
232 info << _("Maschine2 control surface intialized");
235 error << _("Maschine2 Studio is not yet supported");
241 _canvas = new Maschine2Canvas (*this, _hw);
244 Glib::RefPtr<Glib::TimeoutSource> write_timeout = Glib::TimeoutSource::create (40);
245 write_connection = write_timeout->connect (sigc::mem_fun (*this, &Maschine2::dev_write));
246 write_timeout->attach (main_loop()->get_context());
248 #ifdef PLATFORM_WINDOWS
249 Glib::RefPtr<Glib::TimeoutSource> read_timeout = Glib::TimeoutSource::create (20);
251 Glib::RefPtr<Glib::TimeoutSource> read_timeout = Glib::TimeoutSource::create (1);
253 read_connection = read_timeout->connect (sigc::mem_fun (*this, &Maschine2::dev_read));
254 read_timeout->attach (main_loop ()->get_context());
257 tl = new TestLayout (*this, *session, "test");
258 tl->get_menu ()->set_control (_ctrl->encoder (1));
259 tl->get_knob ()->set_control (_ctrl->encoder (2));
268 read_connection.disconnect ();
269 write_connection.disconnect ();
271 session_connections.drop_connections ();
272 button_connections.drop_connections ();
274 if (_handle && _hw) {
276 _hw->write (_handle, NULL);
285 AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*> (_output_port);
286 asp->drain (10000, 500000);
288 AudioEngine::instance()->unregister_port (_midi_out);
289 _midi_out.reset ((ARDOUR::Port*) 0);
304 Maschine2::thread_init ()
306 pthread_set_name (event_loop_name().c_str());
307 ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 1024);
308 PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 1024);
310 struct sched_param rtparam;
311 memset (&rtparam, 0, sizeof (rtparam));
312 rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
313 if (pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam) != 0) {
314 // do we care? not particularly.
319 Maschine2::run_event_loop ()
325 Maschine2::stop_event_loop ()
331 Maschine2::dev_read ()
333 _hw->read (_handle, _ctrl);
338 Maschine2::dev_write ()
340 _hw->write (_handle, _ctrl);
344 // move to callbacks.c || M2Contols implementation
346 Maschine2::current_layout() const