2 Copyright (C) 2016 Paul Davis
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 of the License, or
7 (at your option) any later version.
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
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "pbd/compose.h"
22 #include "pbd/convert.h"
23 #include "pbd/debug.h"
24 #include "pbd/failed_constructor.h"
25 #include "pbd/file_utils.h"
26 #include "pbd/search_path.h"
27 #include "pbd/enumwriter.h"
29 #include "midi++/parser.h"
30 #include "timecode/time.h"
31 #include "timecode/bbt_time.h"
33 #include "ardour/async_midi_port.h"
34 #include "ardour/audioengine.h"
35 #include "ardour/debug.h"
36 #include "ardour/filesystem_paths.h"
37 #include "ardour/midiport_manager.h"
38 #include "ardour/midi_track.h"
39 #include "ardour/midi_port.h"
40 #include "ardour/session.h"
41 #include "ardour/tempo.h"
43 #include "gtkmm2ext/rgb_macros.h"
45 #include "canvas/colors.h"
52 #include "track_mix.h"
57 using namespace ARDOUR;
61 using namespace ArdourSurface;
63 #include "pbd/abstract_ui.cc" // instantiate template
65 const int Push2::cols = 960;
66 const int Push2::rows = 160;
67 const int Push2::pixels_per_row = 1024;
69 #define ABLETON 0x2982
72 __attribute__((constructor)) static void
75 EnumWriter& enum_writer (EnumWriter::instance());
79 MusicalMode::Type mode;
81 #define REGISTER(e) enum_writer.register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
82 #define REGISTER_CLASS_ENUM(t,e) i.push_back (t::e); s.push_back (#e)
84 REGISTER_CLASS_ENUM (MusicalMode,Dorian);
85 REGISTER_CLASS_ENUM (MusicalMode, IonianMajor);
86 REGISTER_CLASS_ENUM (MusicalMode, Minor);
87 REGISTER_CLASS_ENUM (MusicalMode, HarmonicMinor);
88 REGISTER_CLASS_ENUM (MusicalMode, MelodicMinorAscending);
89 REGISTER_CLASS_ENUM (MusicalMode, MelodicMinorDescending);
90 REGISTER_CLASS_ENUM (MusicalMode, Phrygian);
91 REGISTER_CLASS_ENUM (MusicalMode, Lydian);
92 REGISTER_CLASS_ENUM (MusicalMode, Mixolydian);
93 REGISTER_CLASS_ENUM (MusicalMode, Aeolian);
94 REGISTER_CLASS_ENUM (MusicalMode, Locrian);
95 REGISTER_CLASS_ENUM (MusicalMode, PentatonicMajor);
96 REGISTER_CLASS_ENUM (MusicalMode, PentatonicMinor);
97 REGISTER_CLASS_ENUM (MusicalMode, Chromatic);
98 REGISTER_CLASS_ENUM (MusicalMode, BluesScale);
99 REGISTER_CLASS_ENUM (MusicalMode, NeapolitanMinor);
100 REGISTER_CLASS_ENUM (MusicalMode, NeapolitanMajor);
101 REGISTER_CLASS_ENUM (MusicalMode, Oriental);
102 REGISTER_CLASS_ENUM (MusicalMode, DoubleHarmonic);
103 REGISTER_CLASS_ENUM (MusicalMode, Enigmatic);
104 REGISTER_CLASS_ENUM (MusicalMode, Hirajoshi);
105 REGISTER_CLASS_ENUM (MusicalMode, HungarianMinor);
106 REGISTER_CLASS_ENUM (MusicalMode, HungarianMajor);
107 REGISTER_CLASS_ENUM (MusicalMode, Kumoi);
108 REGISTER_CLASS_ENUM (MusicalMode, Iwato);
109 REGISTER_CLASS_ENUM (MusicalMode, Hindu);
110 REGISTER_CLASS_ENUM (MusicalMode, Spanish8Tone);
111 REGISTER_CLASS_ENUM (MusicalMode, Pelog);
112 REGISTER_CLASS_ENUM (MusicalMode, HungarianGypsy);
113 REGISTER_CLASS_ENUM (MusicalMode, Overtone);
114 REGISTER_CLASS_ENUM (MusicalMode, LeadingWholeTone);
115 REGISTER_CLASS_ENUM (MusicalMode, Arabian);
116 REGISTER_CLASS_ENUM (MusicalMode, Balinese);
117 REGISTER_CLASS_ENUM (MusicalMode, Gypsy);
118 REGISTER_CLASS_ENUM (MusicalMode, Mohammedan);
119 REGISTER_CLASS_ENUM (MusicalMode, Javanese);
120 REGISTER_CLASS_ENUM (MusicalMode, Persian);
121 REGISTER_CLASS_ENUM (MusicalMode, Algerian);
125 Push2::Push2 (ARDOUR::Session& s)
126 : ControlProtocol (s, string (X_("Ableton Push 2")))
127 , AbstractUI<Push2Request> (name())
130 , frame_buffer (Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, cols, rows))
131 , _modifier_state (None)
133 , _current_layout (0)
135 , connection_state (ConnectionState (0))
137 , _mode (MusicalMode::IonianMajor)
144 context = Cairo::Context::create (frame_buffer);
150 /* master cannot be removed, so no need to connect to going-away signal */
151 master = session->master_out ();
154 throw failed_constructor ();
157 ControlProtocol::StripableSelectionChanged.connect (selection_connection, MISSING_INVALIDATOR, boost::bind (&Push2::stripable_selection_change, this, _1), this);
159 /* catch current selection, if any */
161 StripableNotificationListPtr sp (new StripableNotificationList (ControlProtocol::last_selected()));
162 stripable_selection_change (sp);
165 /* catch arrival and departure of Push2 itself */
166 ARDOUR::AudioEngine::instance()->PortRegisteredOrUnregistered.connect (port_reg_connection, MISSING_INVALIDATOR, boost::bind (&Push2::port_registration_handler, this), this);
168 /* Catch port connections and disconnections */
169 ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR, boost::bind (&Push2::connection_handler, this, _1, _2, _3, _4, _5), this);
171 /* ports might already be there */
172 port_registration_handler ();
181 Push2::port_registration_handler ()
183 if (_async_in->connected() && _async_out->connected()) {
184 /* don't waste cycles here */
188 string input_port_name = X_("Ableton Push 2 MIDI 1 in");
189 string output_port_name = X_("Ableton Push 2 MIDI 1 out");
193 AudioEngine::instance()->get_ports (string_compose (".*%1", input_port_name), DataType::MIDI, PortFlags (IsPhysical|IsOutput), in);
194 AudioEngine::instance()->get_ports (string_compose (".*%1", output_port_name), DataType::MIDI, PortFlags (IsPhysical|IsInput), out);
196 if (!in.empty() && !out.empty()) {
197 cerr << "Push2: both ports found\n";
198 cerr << "\tconnecting to " << in.front() << " + " << out.front() << endl;
199 if (!_async_in->connected()) {
200 AudioEngine::instance()->connect (_async_in->name(), in.front());
202 if (!_async_out->connected()) {
203 AudioEngine::instance()->connect (_async_out->name(), out.front());
218 if ((handle = libusb_open_device_with_vid_pid (NULL, ABLETON, PUSH2)) == 0) {
222 if ((err = libusb_claim_interface (handle, 0x00))) {
226 device_frame_buffer = new uint16_t[rows*pixels_per_row];
228 memset (device_frame_buffer, 0, sizeof (uint16_t) * rows * pixels_per_row);
230 frame_header[0] = 0xef;
231 frame_header[1] = 0xcd;
232 frame_header[2] = 0xab;
233 frame_header[3] = 0x89;
234 memset (&frame_header[4], 0, 12);
238 _async_in = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("Push 2 in"), true);
239 _async_out = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("Push 2 out"), true);
241 if (_async_in == 0 || _async_out == 0) {
245 /* We do not add our ports to the input/output bundles because we don't
246 * want users wiring them by hand. They could use JACK tools if they
247 * really insist on that.
250 _input_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in).get();
251 _output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_out).get();
253 /* Create a shadow port where, depending on the state of the surface,
254 * we will make pad note on/off events appear. The surface code will
255 * automatically this port to the first selected MIDI track.
258 boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in)->add_shadow_port (string_compose (_("%1 Pads"), X_("Push 2")), boost::bind (&Push2::pad_filter, this, _1, _2));
259 boost::shared_ptr<MidiPort> shadow_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in)->shadow_port();
263 _output_bundle.reset (new ARDOUR::Bundle (_("Push 2 Pads"), false));
265 _output_bundle->add_channel (
267 ARDOUR::DataType::MIDI,
268 session->engine().make_port_name_non_relative (shadow_port->name())
272 session->BundleAddedOrRemoved ();
274 connect_to_parser ();
276 mix_layout = new MixLayout (*this, *session, context);
277 scale_layout = new ScaleLayout (*this, *session, context);
278 track_mix_layout = new TrackMixLayout (*this, *session, context);
280 _current_layout = mix_layout;
285 list<boost::shared_ptr<ARDOUR::Bundle> >
288 list<boost::shared_ptr<ARDOUR::Bundle> > b;
290 if (_output_bundle) {
291 b.push_back (_output_bundle);
300 init_buttons (false);
302 /* wait for button data to be flushed */
304 asp = dynamic_cast<AsyncMIDIPort*> (_output_port);
305 asp->drain (10000, 500000);
307 AudioEngine::instance()->unregister_port (_async_in);
308 AudioEngine::instance()->unregister_port (_async_out);
310 _async_in.reset ((ARDOUR::Port*) 0);
311 _async_out.reset ((ARDOUR::Port*) 0);
315 vblank_connection.disconnect ();
316 periodic_connection.disconnect ();
317 session_connections.drop_connections ();
327 libusb_release_interface (handle, 0x00);
328 libusb_close (handle);
332 delete [] device_frame_buffer;
333 device_frame_buffer = 0;
339 Push2::init_buttons (bool startup)
341 /* This is a list of buttons that we want lit because they do something
342 in ardour related (loosely, sometimes) to their illuminated label.
345 ButtonID buttons[] = { Mute, Solo, Master, Up, Right, Left, Down, Note, Session, Mix, AddTrack, Delete, Undo,
346 Metronome, Shift, Select, Play, RecordEnable, Automate, Repeat, Note, Session, DoubleLoop,
347 Quantize, Duplicate, Browse, PageRight, PageLeft, OctaveUp, OctaveDown, Layout, Scale
350 for (size_t n = 0; n < sizeof (buttons) / sizeof (buttons[0]); ++n) {
351 Button* b = id_button_map[buttons[n]];
354 b->set_color (LED::White);
356 b->set_color (LED::Black);
358 b->set_state (LED::OneShot24th);
359 write (b->state_msg());
362 /* Strip buttons should all be off (black) by default. They will change
363 * color to reflect various conditions
366 ButtonID strip_buttons[] = { Upper1, Upper2, Upper3, Upper4, Upper5, Upper6, Upper7, Upper8,
367 Lower1, Lower2, Lower3, Lower4, Lower5, Lower6, Lower7, Lower8, };
369 for (size_t n = 0; n < sizeof (strip_buttons) / sizeof (strip_buttons[0]); ++n) {
370 Button* b = id_button_map[strip_buttons[n]];
372 b->set_color (LED::Black);
373 b->set_state (LED::OneShot24th);
374 write (b->state_msg());
379 /* all other buttons are off (black) */
381 ButtonID off_buttons[] = { TapTempo, Setup, User, Stop, Convert, New, FixedLength,
382 Fwd32ndT, Fwd32nd, Fwd16thT, Fwd16th, Fwd8thT, Fwd8th, Fwd4trT, Fwd4tr,
383 Accent, Note, Session, };
385 for (size_t n = 0; n < sizeof (off_buttons) / sizeof (off_buttons[0]); ++n) {
386 Button* b = id_button_map[off_buttons[n]];
388 b->set_color (LED::Black);
389 b->set_state (LED::OneShot24th);
390 write (b->state_msg());
395 for (NNPadMap::iterator pi = nn_pad_map.begin(); pi != nn_pad_map.end(); ++pi) {
396 Pad* pad = pi->second;
398 pad->set_color (LED::Black);
399 pad->set_state (LED::OneShot24th);
400 write (pad->state_msg());
408 libusb_device_handle *h;
411 if ((h = libusb_open_device_with_vid_pid (NULL, ABLETON, PUSH2)) == 0) {
412 DEBUG_TRACE (DEBUG::Push2, "no Push2 device found\n");
417 DEBUG_TRACE (DEBUG::Push2, "Push2 device located\n");
422 Push2::request_factory (uint32_t num_requests)
424 /* AbstractUI<T>::request_buffer_factory() is a template method only
425 instantiated in this source module. To provide something visible for
426 use in the interface/descriptor, we have this static method that is
429 return request_buffer_factory (num_requests);
433 Push2::do_request (Push2Request * req)
435 DEBUG_TRACE (DEBUG::Push2, string_compose ("doing request type %1\n", req->type));
436 if (req->type == CallSlot) {
438 call_slot (MISSING_INVALIDATOR, req->the_slot);
440 } else if (req->type == Quit) {
454 /** render host-side frame buffer (a Cairo ImageSurface) to the current
455 * device-side frame buffer. The device frame buffer will be pushed to the
456 * device on the next call to vblank()
460 Push2::blit_to_device_frame_buffer ()
462 /* ensure that all drawing has been done before we fetch pixel data */
464 frame_buffer->flush ();
466 const int stride = 3840; /* bytes per row for Cairo::FORMAT_ARGB32 */
467 const uint8_t* data = frame_buffer->get_data ();
469 /* fill frame buffer (320kB) */
471 uint16_t* fb = (uint16_t*) device_frame_buffer;
473 for (int row = 0; row < rows; ++row) {
475 const uint8_t* dp = data + row * stride;
477 for (int col = 0; col < cols; ++col) {
479 /* fetch r, g, b (range 0..255). Ignore alpha */
481 const int r = (*((const uint32_t*)dp) >> 16) & 0xff;
482 const int g = (*((const uint32_t*)dp) >> 8) & 0xff;
483 const int b = *((const uint32_t*)dp) & 0xff;
485 /* convert to 5 bits, 6 bits, 5 bits, respectively */
486 /* generate 16 bit BGB565 value */
488 *fb++ = (r >> 3) | ((g & 0xfc) << 3) | ((b & 0xf8) << 8);
490 /* the push2 docs state that we should xor the pixel
491 * data. Doing so doesn't work correctly, and not doing
492 * so seems to work fine (colors roughly match intended
499 /* skip 128 bytes to next line. This is filler, used to avoid line borders occuring in the middle of 512
503 fb += 64; /* 128 bytes = 64 int16_t */
514 /* display splash for 3 seconds */
516 if (get_microseconds() - splash_start > 3000000) {
523 Glib::Threads::Mutex::Lock lm (layout_lock, Glib::Threads::TRY_LOCK);
526 /* can't get layout, no re-render needed */
530 bool render_needed = false;
532 if (drawn_layout != _current_layout) {
533 render_needed = true;
536 bool dirty = _current_layout->redraw (context);
537 drawn_layout = _current_layout;
539 return dirty || render_needed;
546 const int timeout_msecs = 1000;
549 if ((err = libusb_bulk_transfer (handle, 0x01, frame_header, sizeof (frame_header), &transferred, timeout_msecs))) {
555 blit_to_device_frame_buffer ();
558 if ((err = libusb_bulk_transfer (handle, 0x01, (uint8_t*) device_frame_buffer , 2 * rows * pixels_per_row, &transferred, timeout_msecs))) {
566 Push2::set_active (bool yn)
568 DEBUG_TRACE (DEBUG::Push2, string_compose("Push2Protocol::set_active init with yn: '%1'\n", yn));
570 if (yn == active()) {
576 /* start event loop */
581 DEBUG_TRACE (DEBUG::Push2, "device open failed\n");
586 /* Connect input port to event loop */
590 asp = dynamic_cast<AsyncMIDIPort*> (_input_port);
591 asp->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &Push2::midi_input_handler), _input_port));
592 asp->xthread().attach (main_loop()->get_context());
594 connect_session_signals ();
596 /* set up periodic task used to push a frame buffer to the
597 * device (25fps). The device can handle 60fps, but we don't
598 * need that frame rate.
601 Glib::RefPtr<Glib::TimeoutSource> vblank_timeout = Glib::TimeoutSource::create (40); // milliseconds
602 vblank_connection = vblank_timeout->connect (sigc::mem_fun (*this, &Push2::vblank));
603 vblank_timeout->attach (main_loop()->get_context());
606 Glib::RefPtr<Glib::TimeoutSource> periodic_timeout = Glib::TimeoutSource::create (1000); // milliseconds
607 periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this, &Push2::periodic));
608 periodic_timeout->attach (main_loop()->get_context());
612 set_pad_scale (_scale_root, _root_octave, _mode, _in_key);
622 ControlProtocol::set_active (yn);
624 DEBUG_TRACE (DEBUG::Push2, string_compose("Push2Protocol::set_active done with yn: '%1'\n", yn));
630 Push2::init_touch_strip ()
632 MidiByteArray msg (9, 0xf0, 0x00, 0x21, 0x1d, 0x01, 0x01, 0x17, 0x00, 0xf7);
633 /* flags are the final byte (ignore end-of-sysex */
635 /* show bar, not point
639 msg[7] = (1<<4) | (1<<5) | (1<<6);
644 Push2::write (const MidiByteArray& data)
646 /* immediate delivery */
647 _output_port->write (&data[0], data.size(), 0);
651 Push2::midi_input_handler (IOCondition ioc, MIDI::Port* port)
654 DEBUG_TRACE (DEBUG::Push2, "MIDI port closed\n");
660 // DEBUG_TRACE (DEBUG::Push2, string_compose ("something happend on %1\n", port->name()));
662 AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*>(port);
667 //DEBUG_TRACE (DEBUG::Push2, string_compose ("data available on %1\n", port->name()));
668 framepos_t now = AudioEngine::instance()->sample_time();
682 Push2::connect_to_parser ()
684 DEBUG_TRACE (DEBUG::Push2, string_compose ("Connecting to signals on port %2\n", _input_port->name()));
686 MIDI::Parser* p = _input_port->parser();
689 p->sysex.connect_same_thread (*this, boost::bind (&Push2::handle_midi_sysex, this, _1, _2, _3));
690 /* V-Pot messages are Controller */
691 p->controller.connect_same_thread (*this, boost::bind (&Push2::handle_midi_controller_message, this, _1, _2));
692 /* Button messages are NoteOn */
693 p->note_on.connect_same_thread (*this, boost::bind (&Push2::handle_midi_note_on_message, this, _1, _2));
694 /* Button messages are NoteOn but libmidi++ sends note-on w/velocity = 0 as note-off so catch them too */
695 p->note_off.connect_same_thread (*this, boost::bind (&Push2::handle_midi_note_on_message, this, _1, _2));
696 /* Fader messages are Pitchbend */
697 p->channel_pitchbend[0].connect_same_thread (*this, boost::bind (&Push2::handle_midi_pitchbend_message, this, _1, _2));
701 Push2::handle_midi_sysex (MIDI::Parser&, MIDI::byte* raw_bytes, size_t sz)
703 DEBUG_TRACE (DEBUG::Push2, string_compose ("Sysex, %1 bytes\n", sz));
707 Push2::handle_midi_controller_message (MIDI::Parser&, MIDI::EventTwoBytes* ev)
709 DEBUG_TRACE (DEBUG::Push2, string_compose ("CC %1 (value %2)\n", (int) ev->controller_number, (int) ev->value));
711 CCButtonMap::iterator b = cc_button_map.find (ev->controller_number);
714 /* any press cancels any pending long press timeouts */
715 for (set<ButtonID>::iterator x = buttons_down.begin(); x != buttons_down.end(); ++x) {
716 Button* bb = id_button_map[*x];
717 bb->timeout_connection.disconnect ();
721 if (b != cc_button_map.end()) {
723 Button* button = b->second;
726 buttons_down.insert (button->id);
727 start_press_timeout (*button, button->id);
729 buttons_down.erase (button->id);
730 button->timeout_connection.disconnect ();
734 set<ButtonID>::iterator c = consumed.find (button->id);
736 if (c == consumed.end()) {
737 if (ev->value == 0) {
738 (this->*button->release_method)();
740 (this->*button->press_method)();
743 DEBUG_TRACE (DEBUG::Push2, "button was consumed, ignored\n");
751 int delta = ev->value;
754 delta = -(128 - delta);
757 switch (ev->controller_number) {
759 _current_layout->strip_vpot (0, delta);
762 _current_layout->strip_vpot (1, delta);
765 _current_layout->strip_vpot (2, delta);
768 _current_layout->strip_vpot (3, delta);
771 _current_layout->strip_vpot (4, delta);
774 _current_layout->strip_vpot (5, delta);
777 _current_layout->strip_vpot (6, delta);
780 _current_layout->strip_vpot (7, delta);
785 other_vpot (8, delta);
788 other_vpot (1, delta);
793 other_vpot (2, delta);
800 Push2::handle_midi_note_on_message (MIDI::Parser& parser, MIDI::EventTwoBytes* ev)
802 DEBUG_TRACE (DEBUG::Push2, string_compose ("Note On %1 (velocity %2)\n", (int) ev->note_number, (int) ev->velocity));
804 if (ev->velocity == 0) {
805 handle_midi_note_off_message (parser, ev);
809 switch (ev->note_number) {
811 _current_layout->strip_vpot_touch (0, ev->velocity > 64);
814 _current_layout->strip_vpot_touch (1, ev->velocity > 64);
817 _current_layout->strip_vpot_touch (2, ev->velocity > 64);
820 _current_layout->strip_vpot_touch (3, ev->velocity > 64);
823 _current_layout->strip_vpot_touch (4, ev->velocity > 64);
826 _current_layout->strip_vpot_touch (5, ev->velocity > 64);
829 _current_layout->strip_vpot_touch (6, ev->velocity > 64);
832 _current_layout->strip_vpot_touch (7, ev->velocity > 64);
837 other_vpot_touch (0, ev->velocity > 64);
840 other_vpot_touch (1, ev->velocity > 64);
845 other_vpot_touch (3, ev->velocity > 64);
850 if (ev->velocity < 64) {
856 if (ev->note_number < 11) {
862 NNPadMap::iterator pi = nn_pad_map.find (ev->note_number);
864 if (pi == nn_pad_map.end()) {
868 Pad* pad = pi->second;
870 if (pad->do_when_pressed == Pad::FlashOn) {
871 pad->set_color (LED::White);
872 pad->set_state (LED::OneShot24th);
873 write (pad->state_msg());
874 } else if (pad->do_when_pressed == Pad::FlashOff) {
875 pad->set_color (LED::Black);
876 pad->set_state (LED::OneShot24th);
877 write (pad->state_msg());
882 Push2::handle_midi_note_off_message (MIDI::Parser&, MIDI::EventTwoBytes* ev)
884 DEBUG_TRACE (DEBUG::Push2, string_compose ("Note Off %1 (velocity %2)\n", (int) ev->note_number, (int) ev->velocity));
886 if (ev->note_number < 11) {
887 /* theoretically related to encoder touch start/end, but
888 * actually they send note on with two different velocity
894 NNPadMap::iterator pi = nn_pad_map.find (ev->note_number);
896 if (pi == nn_pad_map.end()) {
900 Pad* pad = pi->second;
902 if (pad->do_when_pressed == Pad::FlashOn) {
903 pad->set_color (LED::Black);
904 pad->set_state (LED::OneShot24th);
905 write (pad->state_msg());
906 } else if (pad->do_when_pressed == Pad::FlashOff) {
907 pad->set_color (pad->perma_color);
908 pad->set_state (LED::OneShot24th);
909 write (pad->state_msg());
914 Push2::handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t pb)
919 Push2::thread_init ()
921 struct sched_param rtparam;
923 pthread_set_name (event_loop_name().c_str());
925 PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
926 ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
928 memset (&rtparam, 0, sizeof (rtparam));
929 rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
931 if (pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam) != 0) {
932 // do we care? not particularly.
937 Push2::connect_session_signals()
939 // receive routes added
940 //session->RouteAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_routes_added, this, _1), this);
941 // receive VCAs added
942 //session->vca_manager().VCAAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_vca_added, this, _1), this);
944 // receive record state toggled
945 session->RecordStateChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_record_state_changed, this), this);
946 // receive transport state changed
947 session->TransportStateChange.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_transport_state_changed, this), this);
948 session->TransportLooped.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_loop_state_changed, this), this);
949 // receive punch-in and punch-out
950 Config->ParameterChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_parameter_changed, this, _1), this);
951 session->config.ParameterChanged.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_parameter_changed, this, _1), this);
952 // receive rude solo changed
953 session->SoloActive.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_solo_active_changed, this, _1), this);
957 Push2::notify_record_state_changed ()
959 IDButtonMap::iterator b = id_button_map.find (RecordEnable);
961 if (b == id_button_map.end()) {
965 switch (session->record_status ()) {
966 case Session::Disabled:
967 b->second->set_color (LED::White);
968 b->second->set_state (LED::NoTransition);
970 case Session::Enabled:
971 b->second->set_color (LED::Red);
972 b->second->set_state (LED::Blinking4th);
974 case Session::Recording:
975 b->second->set_color (LED::Red);
976 b->second->set_state (LED::OneShot24th);
980 write (b->second->state_msg());
984 Push2::notify_transport_state_changed ()
986 Button* b = id_button_map[Play];
988 if (session->transport_rolling()) {
989 b->set_state (LED::OneShot24th);
990 b->set_color (LED::Green);
993 /* disable any blink on FixedLength from pending edit range op */
994 Button* fl = id_button_map[FixedLength];
996 fl->set_color (LED::Black);
997 fl->set_state (LED::NoTransition);
998 write (fl->state_msg());
1000 b->set_color (LED::White);
1001 b->set_state (LED::NoTransition);
1004 write (b->state_msg());
1008 Push2::notify_loop_state_changed ()
1013 Push2::notify_parameter_changed (std::string param)
1015 IDButtonMap::iterator b;
1017 if (param == "clicking") {
1018 if ((b = id_button_map.find (Metronome)) == id_button_map.end()) {
1021 if (Config->get_clicking()) {
1022 b->second->set_state (LED::Blinking4th);
1023 b->second->set_color (LED::White);
1025 b->second->set_color (LED::White);
1026 b->second->set_state (LED::NoTransition);
1028 write (b->second->state_msg ());
1033 Push2::notify_solo_active_changed (bool yn)
1035 IDButtonMap::iterator b = id_button_map.find (Solo);
1037 if (b == id_button_map.end()) {
1042 b->second->set_state (LED::Blinking4th);
1043 b->second->set_color (LED::Red);
1045 b->second->set_state (LED::NoTransition);
1046 b->second->set_color (LED::White);
1049 write (b->second->state_msg());
1055 XMLNode& node (ControlProtocol::get_state());
1058 child = new XMLNode (X_("Input"));
1059 child->add_child_nocopy (_async_in->get_state());
1060 node.add_child_nocopy (*child);
1061 child = new XMLNode (X_("Output"));
1062 child->add_child_nocopy (_async_out->get_state());
1063 node.add_child_nocopy (*child);
1065 node.add_property (X_("root"), to_string (_scale_root, std::dec));
1066 node.add_property (X_("root_octave"), to_string (_root_octave, std::dec));
1067 node.add_property (X_("in_key"), _in_key ? X_("yes") : X_("no"));
1068 node.add_property (X_("mode"), enum_2_string (_mode));
1074 Push2::set_state (const XMLNode & node, int version)
1076 DEBUG_TRACE (DEBUG::Push2, string_compose ("Push2::set_state: active %1\n", active()));
1080 if (ControlProtocol::set_state (node, version)) {
1086 if ((child = node.child (X_("Input"))) != 0) {
1087 XMLNode* portnode = child->child (Port::state_node_name.c_str());
1089 _async_in->set_state (*portnode, version);
1093 if ((child = node.child (X_("Output"))) != 0) {
1094 XMLNode* portnode = child->child (Port::state_node_name.c_str());
1096 _async_out->set_state (*portnode, version);
1100 XMLProperty const* prop;
1102 if ((prop = node.property (X_("root"))) != 0) {
1103 _scale_root = atoi (prop->value());
1106 if ((prop = node.property (X_("root_octave"))) != 0) {
1107 _root_octave = atoi (prop->value());
1110 if ((prop = node.property (X_("in_key"))) != 0) {
1111 _in_key = string_is_affirmative (prop->value());
1114 if ((prop = node.property (X_("mode"))) != 0) {
1115 _mode = (MusicalMode::Type) string_2_enum (prop->value(), _mode);
1122 Push2::other_vpot (int n, int delta)
1130 /* master gain control */
1132 boost::shared_ptr<AutomationControl> ac = master->gain_control();
1134 ac->set_value (ac->get_value() + ((2.0/64.0) * delta), PBD::Controllable::UseGroup);
1142 Push2::other_vpot_touch (int n, bool touching)
1151 boost::shared_ptr<AutomationControl> ac = master->gain_control();
1154 ac->start_touch (session->audible_frame());
1156 ac->stop_touch (true, session->audible_frame());
1164 Push2::start_shift ()
1166 cerr << "start shift\n";
1167 _modifier_state = ModifierState (_modifier_state | ModShift);
1168 Button* b = id_button_map[Shift];
1169 b->set_color (LED::White);
1170 b->set_state (LED::Blinking16th);
1171 write (b->state_msg());
1177 if (_modifier_state & ModShift) {
1178 cerr << "end shift\n";
1179 _modifier_state = ModifierState (_modifier_state & ~(ModShift));
1180 Button* b = id_button_map[Shift];
1181 b->timeout_connection.disconnect ();
1182 b->set_color (LED::White);
1183 b->set_state (LED::OneShot24th);
1184 write (b->state_msg());
1191 std::string splash_file;
1193 Searchpath rc (ARDOUR::ardour_data_search_path());
1194 rc.add_subdirectory_to_paths ("resources");
1196 if (!find_file (rc, PROGRAM_NAME "-splash.png", splash_file)) {
1197 cerr << "Cannot find splash screen image file\n";
1198 throw failed_constructor();
1201 Cairo::RefPtr<Cairo::ImageSurface> img = Cairo::ImageSurface::create_from_png (splash_file);
1203 double x_ratio = (double) img->get_width() / (cols - 20);
1204 double y_ratio = (double) img->get_height() / (rows - 20);
1205 double scale = min (x_ratio, y_ratio);
1209 context->set_source_rgb (0.764, 0.882, 0.882);
1215 context->translate (5, 5);
1216 context->scale (scale, scale);
1217 context->set_source (img, 0, 0);
1219 context->restore ();
1223 Glib::RefPtr<Pango::Layout> some_text = Pango::Layout::create (context);
1225 Pango::FontDescription fd ("Sans 38");
1226 some_text->set_font_description (fd);
1227 some_text->set_text (string_compose ("%1 %2", PROGRAM_NAME, VERSIONSTRING));
1229 context->move_to (200, 10);
1230 context->set_source_rgb (0, 0, 0);
1231 some_text->update_from_cairo_context (context);
1232 some_text->show_in_cairo_context (context);
1234 Pango::FontDescription fd2 ("Sans Italic 18");
1235 some_text->set_font_description (fd2);
1236 some_text->set_text (_("Ableton Push 2 Support"));
1238 context->move_to (200, 80);
1239 context->set_source_rgb (0, 0, 0);
1240 some_text->update_from_cairo_context (context);
1241 some_text->show_in_cairo_context (context);
1243 splash_start = get_microseconds ();
1244 blit_to_device_frame_buffer ();
1248 Push2::pad_filter (MidiBuffer& in, MidiBuffer& out) const
1250 /* This filter is called asynchronously from a realtime process
1251 context. It must use atomics to check state, and must not block.
1254 bool matched = false;
1256 for (MidiBuffer::iterator ev = in.begin(); ev != in.end(); ++ev) {
1257 if ((*ev).is_note_on() || (*ev).is_note_off()) {
1259 /* encoder touch start/touch end use note
1260 * 0-10. touchstrip uses note 12
1263 if ((*ev).note() > 10 && (*ev).note() != 12) {
1265 const int n = (*ev).note ();
1266 NNPadMap::const_iterator nni = nn_pad_map.find (n);
1268 if (nni != nn_pad_map.end()) {
1269 Pad const * pad = nni->second;
1270 /* shift for output to the shadow port */
1271 if (pad->filtered >= 0) {
1272 (*ev).set_note (pad->filtered + (octave_shift*12));
1273 out.push_back (*ev);
1274 /* shift back so that the pads light correctly */
1277 /* no mapping, don't send event */
1280 out.push_back (*ev);
1285 } else if ((*ev).is_pitch_bender() || (*ev).is_aftertouch() || (*ev).is_channel_pressure()) {
1286 out.push_back (*ev);
1294 Push2::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
1296 DEBUG_TRACE (DEBUG::FaderPort, "FaderPort::connection_handler start\n");
1297 if (!_input_port || !_output_port) {
1301 string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_async_in)->name());
1302 string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_async_out)->name());
1304 if (ni == name1 || ni == name2) {
1306 connection_state |= InputConnected;
1308 connection_state &= ~InputConnected;
1310 } else if (no == name1 || no == name2) {
1312 connection_state |= OutputConnected;
1314 connection_state &= ~OutputConnected;
1317 DEBUG_TRACE (DEBUG::FaderPort, string_compose ("Connections between %1 and %2 changed, but I ignored it\n", name1, name2));
1322 if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
1324 /* XXX this is a horrible hack. Without a short sleep here,
1325 something prevents the device wakeup messages from being
1326 sent and/or the responses from being received.
1330 DEBUG_TRACE (DEBUG::FaderPort, "device now connected for both input and output\n");
1334 DEBUG_TRACE (DEBUG::FaderPort, "Device disconnected (input or output or both) or not yet fully connected\n");
1337 ConnectionChange (); /* emit signal for our GUI */
1339 DEBUG_TRACE (DEBUG::FaderPort, "FaderPort::connection_handler end\n");
1341 return true; /* connection status changed */
1344 boost::shared_ptr<Port>
1345 Push2::output_port()
1350 boost::shared_ptr<Port>
1357 Push2::pad_note (int row, int col) const
1359 NNPadMap::const_iterator nni = nn_pad_map.find (36+(row*8)+col);
1361 if (nni != nn_pad_map.end()) {
1362 return nni->second->filtered;
1369 Push2::set_pad_scale (int root, int octave, MusicalMode::Type mode, bool inkey)
1371 MusicalMode m (mode);
1372 vector<float>::iterator interval;
1374 const int original_root = root;
1376 interval = m.steps.begin();
1377 root += (octave*12);
1380 const int root_start = root;
1382 set<int> mode_map; /* contains only notes in mode, O(logN) lookup */
1383 vector<int> mode_vector; /* sorted in note order */
1385 mode_map.insert (note);
1386 mode_vector.push_back (note);
1388 /* build a map of all notes in the mode, from the root to 127 */
1390 while (note < 128) {
1392 if (interval == m.steps.end()) {
1394 /* last distance was the end of the scale,
1395 so wrap, adding the next note at one
1396 octave above the last root.
1399 interval = m.steps.begin();
1401 mode_map.insert (root);
1402 mode_vector.push_back (root);
1405 note = (int) floor (root + (2.0 * (*interval)));
1407 mode_map.insert (note);
1408 mode_vector.push_back (note);
1414 vector<int>::iterator notei;
1416 for (int row = 0; row < 8; ++row) {
1418 /* Ableton's grid layout wraps the available notes in the scale
1419 * by offsetting 3 notes per row (from the bottom)
1422 notei = mode_vector.begin();
1423 notei += row_offset;
1426 for (int col = 0; col < 8; ++col) {
1427 int index = 36 + (row*8) + col;
1428 Pad* pad = nn_pad_map[index];
1430 if (notei != mode_vector.end()) {
1433 pad->filtered = notenum;
1435 if ((notenum % 12) == original_root) {
1436 pad->set_color (LED::Green);
1437 pad->perma_color = LED::Green;
1439 pad->set_color (LED::White);
1440 pad->perma_color = LED::White;
1443 pad->do_when_pressed = Pad::FlashOff;
1448 pad->set_color (LED::Black);
1449 pad->do_when_pressed = Pad::Nothing;
1453 write (pad->state_msg());
1459 /* chromatic: all notes available, but highlight those in the scale */
1461 for (note = 36; note < 100; ++note) {
1463 Pad* pad = nn_pad_map[note];
1465 /* Chromatic: all pads play, half-tone steps. Light
1466 * those in the scale, and highlight root notes
1469 pad->filtered = root_start + (note - 36);
1471 if (mode_map.find (note) != mode_map.end()) {
1473 if ((note % 12) == original_root) {
1474 pad->set_color (LED::Green);
1475 pad->perma_color = LED::Green;
1477 pad->set_color (LED::White);
1478 pad->perma_color = LED::White;
1481 pad->do_when_pressed = Pad::FlashOff;
1485 /* note is not in mode, turn it off */
1487 pad->do_when_pressed = Pad::FlashOn;
1488 pad->set_color (LED::Black);
1492 write (pad->state_msg());
1496 PadChange (); /* EMIT SIGNAL */
1500 _scale_root = original_root;
1501 _root_octave = octave;
1507 Push2::set_percussive_mode (bool yn)
1510 cerr << "back to scale\n";
1511 set_pad_scale (_scale_root, _root_octave, _mode, _in_key);
1518 for (int row = 0; row < 8; ++row) {
1520 for (int col = 0; col < 4; ++col) {
1522 int index = 36 + (row*8) + col;
1523 Pad* pad = nn_pad_map[index];
1525 pad->filtered = drum_note;
1530 for (int row = 0; row < 8; ++row) {
1532 for (int col = 4; col < 8; ++col) {
1534 int index = 36 + (row*8) + col;
1535 Pad* pad = nn_pad_map[index];
1537 pad->filtered = drum_note;
1544 PadChange (); /* EMIT SIGNAL */
1548 Push2::current_layout () const
1550 Glib::Threads::Mutex::Lock lm (layout_lock);
1551 return _current_layout;
1555 Push2::stripable_selection_change (StripableNotificationListPtr selected)
1557 boost::shared_ptr<MidiPort> pad_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in)->shadow_port();
1558 boost::shared_ptr<MidiTrack> current_midi_track = current_pad_target.lock();
1559 boost::shared_ptr<MidiTrack> new_pad_target;
1561 /* See if there's a MIDI track selected */
1563 for (StripableNotificationList::iterator si = selected->begin(); si != selected->end(); ++si) {
1565 new_pad_target = boost::dynamic_pointer_cast<MidiTrack> ((*si).lock());
1567 if (new_pad_target) {
1572 if (new_pad_target) {
1573 cerr << "new midi pad target " << new_pad_target->name() << endl;
1575 cerr << "no midi pad target\n";
1578 if (current_midi_track == new_pad_target) {
1583 if (!new_pad_target) {
1584 /* leave existing connection alone */
1588 /* disconnect from pad port, if appropriate */
1590 if (current_midi_track && pad_port) {
1591 cerr << "Disconnect pads from " << current_midi_track->name() << endl;
1592 current_midi_track->input()->disconnect (current_midi_track->input()->nth(0), pad_port->name(), this);
1595 /* now connect the pad port to this (newly) selected midi
1596 * track, if indeed there is one.
1599 if (new_pad_target && pad_port) {
1600 cerr << "Reconnect pads to " << new_pad_target->name() << endl;
1601 new_pad_target->input()->connect (new_pad_target->input()->nth (0), pad_port->name(), this);
1602 current_pad_target = new_pad_target;
1604 current_pad_target.reset ();
1609 Push2::button_by_id (ButtonID bid)
1611 return id_button_map[bid];
1615 Push2::get_color_index (uint32_t rgb)
1617 ColorMap::iterator i = color_map.find (rgb);
1619 if (i != color_map.end()) {
1624 UINT_TO_RGBA (rgb, &r, &g, &b, &a);
1625 int w = 204; /* not sure where/when we should get this value */
1627 /* get a free index */
1631 if (color_map_free_list.empty()) {
1632 /* random replacement of any entry above zero and below 122 (where the
1633 * Ableton standard colors live)
1635 index = 1 + (random() % 121);
1637 index = color_map_free_list.top();
1638 color_map_free_list.pop();
1641 MidiByteArray palette_msg (17, 0xf0, 0x00 , 0x21, 0x1d, 0x01, 0x01, 0x03, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x01, 0x7E, 0x00, 0xF7);
1642 MidiByteArray update_pallette_msg (8, 0xf0, 0x00, 0x21, 0x1d, 0x01, 0x01, 0x05, 0xF7);
1644 palette_msg[7] = index;
1645 palette_msg[8] = r & 0x7f;
1646 palette_msg[9] = r & 0x1;
1647 palette_msg[10] = g & 0x7f;
1648 palette_msg[11] = g & 0x1;
1649 palette_msg[12] = b & 0x7f;
1650 palette_msg[13] = b & 0x1;
1651 palette_msg[14] = w & 0x7f;
1652 palette_msg[15] = w & 0x1;
1654 write (palette_msg);
1655 write (update_pallette_msg);
1657 color_map[index] = rgb;
1663 Push2::build_color_map ()
1665 /* These are "standard" colors that Ableton docs suggest will always be
1666 there. Put them in our color map so that when we look up these
1667 colors, we will use the Ableton indices for them.
1670 color_map.insert (make_pair (RGB_TO_UINT (0,0,0), 0));
1671 color_map.insert (make_pair (RGB_TO_UINT (204,204,204), 122));
1672 color_map.insert (make_pair (RGB_TO_UINT (64,64,64), 123));
1673 color_map.insert (make_pair (RGB_TO_UINT (20,20,20), 124));
1674 color_map.insert (make_pair (RGB_TO_UINT (0,0,255), 125));
1675 color_map.insert (make_pair (RGB_TO_UINT (0,255,0), 126));
1676 color_map.insert (make_pair (RGB_TO_UINT (255,0,0), 127));
1678 for (uint8_t n = 1; n < 122; ++n) {
1679 color_map_free_list.push (n);
1684 Push2::fill_color_table ()
1686 colors.insert (make_pair (DarkBackground, ArdourCanvas::rgba_to_color (0, 0, 0, 1)));
1687 colors.insert (make_pair (LightBackground, ArdourCanvas::rgba_to_color (0.98, 0.98, 0.98, 1)));
1689 colors.insert (make_pair (ParameterName, ArdourCanvas::rgba_to_color (0.32, 0.28, 0.47, 1)));
1691 colors.insert (make_pair (KnobArcBackground, ArdourCanvas::rgba_to_color (0.3, 0.3, 0.3, 1.0)));
1692 colors.insert (make_pair (KnobArcStart, ArdourCanvas::rgba_to_color (1.0, 0.0, 0.0, 1.0)));
1693 colors.insert (make_pair (KnobArcEnd, ArdourCanvas::rgba_to_color (0.0, 1.0, 0.0, 1.0)));
1695 colors.insert (make_pair (KnobLineShadow, ArdourCanvas::rgba_to_color (0, 0, 0, 0.3)));
1696 colors.insert (make_pair (KnobLine, ArdourCanvas::rgba_to_color (1, 1, 1, 1)));
1698 colors.insert (make_pair (KnobForeground, ArdourCanvas::rgba_to_color (1, 1, 1, 1)));
1699 colors.insert (make_pair (KnobBackground, ArdourCanvas::rgba_to_color (1, 1, 1, 1)));
1700 colors.insert (make_pair (KnobShadow, ArdourCanvas::rgba_to_color (0, 0, 0, 0.1)));
1701 colors.insert (make_pair (KnobBorder, ArdourCanvas::rgba_to_color (0, 0, 0, 1)));
1706 Push2::get_color (ColorName name)
1708 Colors::iterator c = colors.find (name);
1709 if (c != colors.end()) {