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 cerr << "new push2 @ " << this << "\n";
146 context = Cairo::Context::create (frame_buffer);
152 /* master cannot be removed, so no need to connect to going-away signal */
153 master = session->master_out ();
156 throw failed_constructor ();
159 ControlProtocol::StripableSelectionChanged.connect (selection_connection, MISSING_INVALIDATOR, boost::bind (&Push2::stripable_selection_change, this, _1), this);
161 /* catch current selection, if any */
163 StripableNotificationListPtr sp (new StripableNotificationList (ControlProtocol::last_selected()));
164 stripable_selection_change (sp);
167 /* catch arrival and departure of Push2 itself */
168 ARDOUR::AudioEngine::instance()->PortRegisteredOrUnregistered.connect (port_reg_connection, MISSING_INVALIDATOR, boost::bind (&Push2::port_registration_handler, this), this);
170 /* Catch port connections and disconnections */
171 ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR, boost::bind (&Push2::connection_handler, this, _1, _2, _3, _4, _5), this);
173 /* ports might already be there */
174 port_registration_handler ();
179 cerr << "push2 deleted\n";
184 Push2::port_registration_handler ()
186 cerr << "preg for " << this << endl;
188 if (!_async_in && !_async_out) {
189 /* ports not registered yet */
193 if (_async_in->connected() && _async_out->connected()) {
194 /* don't waste cycles here */
198 string input_port_name = X_("Ableton Push 2 MIDI 1 in");
199 string output_port_name = X_("Ableton Push 2 MIDI 1 out");
203 AudioEngine::instance()->get_ports (string_compose (".*%1", input_port_name), DataType::MIDI, PortFlags (IsPhysical|IsOutput), in);
204 AudioEngine::instance()->get_ports (string_compose (".*%1", output_port_name), DataType::MIDI, PortFlags (IsPhysical|IsInput), out);
206 if (!in.empty() && !out.empty()) {
207 cerr << "Push2: both ports found\n";
208 cerr << "\tconnecting to " << in.front() << " + " << out.front() << endl;
209 if (!_async_in->connected()) {
210 AudioEngine::instance()->connect (_async_in->name(), in.front());
212 if (!_async_out->connected()) {
213 AudioEngine::instance()->connect (_async_out->name(), out.front());
228 if ((handle = libusb_open_device_with_vid_pid (NULL, ABLETON, PUSH2)) == 0) {
232 if ((err = libusb_claim_interface (handle, 0x00))) {
236 device_frame_buffer = new uint16_t[rows*pixels_per_row];
238 memset (device_frame_buffer, 0, sizeof (uint16_t) * rows * pixels_per_row);
240 frame_header[0] = 0xef;
241 frame_header[1] = 0xcd;
242 frame_header[2] = 0xab;
243 frame_header[3] = 0x89;
244 memset (&frame_header[4], 0, 12);
248 _async_in = AudioEngine::instance()->register_input_port (DataType::MIDI, X_("Push 2 in"), true);
249 _async_out = AudioEngine::instance()->register_output_port (DataType::MIDI, X_("Push 2 out"), true);
251 if (_async_in == 0 || _async_out == 0) {
255 /* We do not add our ports to the input/output bundles because we don't
256 * want users wiring them by hand. They could use JACK tools if they
257 * really insist on that.
260 _input_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in).get();
261 _output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_out).get();
263 /* Create a shadow port where, depending on the state of the surface,
264 * we will make pad note on/off events appear. The surface code will
265 * automatically this port to the first selected MIDI track.
268 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));
269 boost::shared_ptr<MidiPort> shadow_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in)->shadow_port();
273 _output_bundle.reset (new ARDOUR::Bundle (_("Push 2 Pads"), false));
275 _output_bundle->add_channel (
277 ARDOUR::DataType::MIDI,
278 session->engine().make_port_name_non_relative (shadow_port->name())
282 session->BundleAddedOrRemoved ();
284 connect_to_parser ();
286 mix_layout = new MixLayout (*this, *session, context);
287 scale_layout = new ScaleLayout (*this, *session, context);
288 track_mix_layout = new TrackMixLayout (*this, *session, context);
293 list<boost::shared_ptr<ARDOUR::Bundle> >
296 list<boost::shared_ptr<ARDOUR::Bundle> > b;
298 if (_output_bundle) {
299 b.push_back (_output_bundle);
308 init_buttons (false);
310 /* wait for button data to be flushed */
312 asp = dynamic_cast<AsyncMIDIPort*> (_output_port);
313 asp->drain (10000, 500000);
315 AudioEngine::instance()->unregister_port (_async_in);
316 AudioEngine::instance()->unregister_port (_async_out);
318 _async_in.reset ((ARDOUR::Port*) 0);
319 _async_out.reset ((ARDOUR::Port*) 0);
323 vblank_connection.disconnect ();
324 periodic_connection.disconnect ();
325 session_connections.drop_connections ();
335 libusb_release_interface (handle, 0x00);
336 libusb_close (handle);
340 delete [] device_frame_buffer;
341 device_frame_buffer = 0;
347 Push2::init_buttons (bool startup)
349 /* This is a list of buttons that we want lit because they do something
350 in ardour related (loosely, sometimes) to their illuminated label.
353 ButtonID buttons[] = { Mute, Solo, Master, Up, Right, Left, Down, Note, Session, Mix, AddTrack, Delete, Undo,
354 Metronome, Shift, Select, Play, RecordEnable, Automate, Repeat, Note, Session, DoubleLoop,
355 Quantize, Duplicate, Browse, PageRight, PageLeft, OctaveUp, OctaveDown, Layout, Scale
358 for (size_t n = 0; n < sizeof (buttons) / sizeof (buttons[0]); ++n) {
359 Button* b = id_button_map[buttons[n]];
362 b->set_color (LED::White);
364 b->set_color (LED::Black);
366 b->set_state (LED::OneShot24th);
367 write (b->state_msg());
370 /* Strip buttons should all be off (black) by default. They will change
371 * color to reflect various conditions
374 ButtonID strip_buttons[] = { Upper1, Upper2, Upper3, Upper4, Upper5, Upper6, Upper7, Upper8,
375 Lower1, Lower2, Lower3, Lower4, Lower5, Lower6, Lower7, Lower8, };
377 for (size_t n = 0; n < sizeof (strip_buttons) / sizeof (strip_buttons[0]); ++n) {
378 Button* b = id_button_map[strip_buttons[n]];
380 b->set_color (LED::Black);
381 b->set_state (LED::OneShot24th);
382 write (b->state_msg());
387 /* all other buttons are off (black) */
389 ButtonID off_buttons[] = { TapTempo, Setup, User, Stop, Convert, New, FixedLength,
390 Fwd32ndT, Fwd32nd, Fwd16thT, Fwd16th, Fwd8thT, Fwd8th, Fwd4trT, Fwd4tr,
391 Accent, Note, Session, };
393 for (size_t n = 0; n < sizeof (off_buttons) / sizeof (off_buttons[0]); ++n) {
394 Button* b = id_button_map[off_buttons[n]];
396 b->set_color (LED::Black);
397 b->set_state (LED::OneShot24th);
398 write (b->state_msg());
403 for (NNPadMap::iterator pi = nn_pad_map.begin(); pi != nn_pad_map.end(); ++pi) {
404 Pad* pad = pi->second;
406 pad->set_color (LED::Black);
407 pad->set_state (LED::OneShot24th);
408 write (pad->state_msg());
416 libusb_device_handle *h;
419 if ((h = libusb_open_device_with_vid_pid (NULL, ABLETON, PUSH2)) == 0) {
420 DEBUG_TRACE (DEBUG::Push2, "no Push2 device found\n");
425 DEBUG_TRACE (DEBUG::Push2, "Push2 device located\n");
430 Push2::request_factory (uint32_t num_requests)
432 /* AbstractUI<T>::request_buffer_factory() is a template method only
433 instantiated in this source module. To provide something visible for
434 use in the interface/descriptor, we have this static method that is
437 return request_buffer_factory (num_requests);
441 Push2::do_request (Push2Request * req)
443 DEBUG_TRACE (DEBUG::Push2, string_compose ("doing request type %1\n", req->type));
444 if (req->type == CallSlot) {
446 call_slot (MISSING_INVALIDATOR, req->the_slot);
448 } else if (req->type == Quit) {
462 /** render host-side frame buffer (a Cairo ImageSurface) to the current
463 * device-side frame buffer. The device frame buffer will be pushed to the
464 * device on the next call to vblank()
468 Push2::blit_to_device_frame_buffer ()
470 /* ensure that all drawing has been done before we fetch pixel data */
472 frame_buffer->flush ();
474 const int stride = 3840; /* bytes per row for Cairo::FORMAT_ARGB32 */
475 const uint8_t* data = frame_buffer->get_data ();
477 /* fill frame buffer (320kB) */
479 uint16_t* fb = (uint16_t*) device_frame_buffer;
481 for (int row = 0; row < rows; ++row) {
483 const uint8_t* dp = data + row * stride;
485 for (int col = 0; col < cols; ++col) {
487 /* fetch r, g, b (range 0..255). Ignore alpha */
489 const int r = (*((const uint32_t*)dp) >> 16) & 0xff;
490 const int g = (*((const uint32_t*)dp) >> 8) & 0xff;
491 const int b = *((const uint32_t*)dp) & 0xff;
493 /* convert to 5 bits, 6 bits, 5 bits, respectively */
494 /* generate 16 bit BGB565 value */
496 *fb++ = (r >> 3) | ((g & 0xfc) << 3) | ((b & 0xf8) << 8);
498 /* the push2 docs state that we should xor the pixel
499 * data. Doing so doesn't work correctly, and not doing
500 * so seems to work fine (colors roughly match intended
507 /* skip 128 bytes to next line. This is filler, used to avoid line borders occuring in the middle of 512
511 fb += 64; /* 128 bytes = 64 int16_t */
522 /* display splash for 3 seconds */
524 if (get_microseconds() - splash_start > 3000000) {
531 Glib::Threads::Mutex::Lock lm (layout_lock, Glib::Threads::TRY_LOCK);
534 /* can't get layout, no re-render needed */
538 bool render_needed = false;
540 if (drawn_layout != _current_layout) {
541 render_needed = true;
544 bool dirty = _current_layout->redraw (context, render_needed);
545 drawn_layout = _current_layout;
547 return dirty || render_needed;
554 const int timeout_msecs = 1000;
557 if ((err = libusb_bulk_transfer (handle, 0x01, frame_header, sizeof (frame_header), &transferred, timeout_msecs))) {
563 blit_to_device_frame_buffer ();
566 if ((err = libusb_bulk_transfer (handle, 0x01, (uint8_t*) device_frame_buffer , 2 * rows * pixels_per_row, &transferred, timeout_msecs))) {
574 Push2::set_active (bool yn)
576 DEBUG_TRACE (DEBUG::Push2, string_compose("Push2Protocol::set_active init with yn: '%1'\n", yn));
578 if (yn == active()) {
584 /* start event loop */
589 DEBUG_TRACE (DEBUG::Push2, "device open failed\n");
594 /* Connect input port to event loop */
598 asp = dynamic_cast<AsyncMIDIPort*> (_input_port);
599 asp->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &Push2::midi_input_handler), _input_port));
600 asp->xthread().attach (main_loop()->get_context());
602 connect_session_signals ();
604 /* set up periodic task used to push a frame buffer to the
605 * device (25fps). The device can handle 60fps, but we don't
606 * need that frame rate.
609 Glib::RefPtr<Glib::TimeoutSource> vblank_timeout = Glib::TimeoutSource::create (40); // milliseconds
610 vblank_connection = vblank_timeout->connect (sigc::mem_fun (*this, &Push2::vblank));
611 vblank_timeout->attach (main_loop()->get_context());
614 Glib::RefPtr<Glib::TimeoutSource> periodic_timeout = Glib::TimeoutSource::create (1000); // milliseconds
615 periodic_connection = periodic_timeout->connect (sigc::mem_fun (*this, &Push2::periodic));
616 periodic_timeout->attach (main_loop()->get_context());
620 set_pad_scale (_scale_root, _root_octave, _mode, _in_key);
622 set_current_layout (mix_layout);
630 ControlProtocol::set_active (yn);
632 DEBUG_TRACE (DEBUG::Push2, string_compose("Push2Protocol::set_active done with yn: '%1'\n", yn));
638 Push2::init_touch_strip ()
640 MidiByteArray msg (9, 0xf0, 0x00, 0x21, 0x1d, 0x01, 0x01, 0x17, 0x00, 0xf7);
641 /* flags are the final byte (ignore end-of-sysex */
643 /* show bar, not point
647 msg[7] = (1<<4) | (1<<5) | (1<<6);
652 Push2::write (const MidiByteArray& data)
654 /* immediate delivery */
655 _output_port->write (&data[0], data.size(), 0);
659 Push2::midi_input_handler (IOCondition ioc, MIDI::Port* port)
662 DEBUG_TRACE (DEBUG::Push2, "MIDI port closed\n");
668 // DEBUG_TRACE (DEBUG::Push2, string_compose ("something happend on %1\n", port->name()));
670 AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*>(port);
675 //DEBUG_TRACE (DEBUG::Push2, string_compose ("data available on %1\n", port->name()));
676 framepos_t now = AudioEngine::instance()->sample_time();
690 Push2::connect_to_parser ()
692 DEBUG_TRACE (DEBUG::Push2, string_compose ("Connecting to signals on port %2\n", _input_port->name()));
694 MIDI::Parser* p = _input_port->parser();
697 p->sysex.connect_same_thread (*this, boost::bind (&Push2::handle_midi_sysex, this, _1, _2, _3));
698 /* V-Pot messages are Controller */
699 p->controller.connect_same_thread (*this, boost::bind (&Push2::handle_midi_controller_message, this, _1, _2));
700 /* Button messages are NoteOn */
701 p->note_on.connect_same_thread (*this, boost::bind (&Push2::handle_midi_note_on_message, this, _1, _2));
702 /* Button messages are NoteOn but libmidi++ sends note-on w/velocity = 0 as note-off so catch them too */
703 p->note_off.connect_same_thread (*this, boost::bind (&Push2::handle_midi_note_on_message, this, _1, _2));
704 /* Fader messages are Pitchbend */
705 p->channel_pitchbend[0].connect_same_thread (*this, boost::bind (&Push2::handle_midi_pitchbend_message, this, _1, _2));
709 Push2::handle_midi_sysex (MIDI::Parser&, MIDI::byte* raw_bytes, size_t sz)
711 DEBUG_TRACE (DEBUG::Push2, string_compose ("Sysex, %1 bytes\n", sz));
715 Push2::handle_midi_controller_message (MIDI::Parser&, MIDI::EventTwoBytes* ev)
717 DEBUG_TRACE (DEBUG::Push2, string_compose ("CC %1 (value %2)\n", (int) ev->controller_number, (int) ev->value));
719 CCButtonMap::iterator b = cc_button_map.find (ev->controller_number);
722 /* any press cancels any pending long press timeouts */
723 for (set<ButtonID>::iterator x = buttons_down.begin(); x != buttons_down.end(); ++x) {
724 Button* bb = id_button_map[*x];
725 bb->timeout_connection.disconnect ();
729 if (b != cc_button_map.end()) {
731 Button* button = b->second;
734 buttons_down.insert (button->id);
735 start_press_timeout (*button, button->id);
737 buttons_down.erase (button->id);
738 button->timeout_connection.disconnect ();
742 set<ButtonID>::iterator c = consumed.find (button->id);
744 if (c == consumed.end()) {
745 if (ev->value == 0) {
746 (this->*button->release_method)();
748 (this->*button->press_method)();
751 DEBUG_TRACE (DEBUG::Push2, "button was consumed, ignored\n");
759 int delta = ev->value;
762 delta = -(128 - delta);
765 switch (ev->controller_number) {
767 _current_layout->strip_vpot (0, delta);
770 _current_layout->strip_vpot (1, delta);
773 _current_layout->strip_vpot (2, delta);
776 _current_layout->strip_vpot (3, delta);
779 _current_layout->strip_vpot (4, delta);
782 _current_layout->strip_vpot (5, delta);
785 _current_layout->strip_vpot (6, delta);
788 _current_layout->strip_vpot (7, delta);
793 other_vpot (8, delta);
796 other_vpot (1, delta);
801 other_vpot (2, delta);
808 Push2::handle_midi_note_on_message (MIDI::Parser& parser, MIDI::EventTwoBytes* ev)
810 DEBUG_TRACE (DEBUG::Push2, string_compose ("Note On %1 (velocity %2)\n", (int) ev->note_number, (int) ev->velocity));
812 if (ev->velocity == 0) {
813 handle_midi_note_off_message (parser, ev);
817 switch (ev->note_number) {
819 _current_layout->strip_vpot_touch (0, ev->velocity > 64);
822 _current_layout->strip_vpot_touch (1, ev->velocity > 64);
825 _current_layout->strip_vpot_touch (2, ev->velocity > 64);
828 _current_layout->strip_vpot_touch (3, ev->velocity > 64);
831 _current_layout->strip_vpot_touch (4, ev->velocity > 64);
834 _current_layout->strip_vpot_touch (5, ev->velocity > 64);
837 _current_layout->strip_vpot_touch (6, ev->velocity > 64);
840 _current_layout->strip_vpot_touch (7, ev->velocity > 64);
845 other_vpot_touch (0, ev->velocity > 64);
848 other_vpot_touch (1, ev->velocity > 64);
853 other_vpot_touch (3, ev->velocity > 64);
858 if (ev->velocity < 64) {
864 if (ev->note_number < 11) {
870 NNPadMap::iterator pi = nn_pad_map.find (ev->note_number);
872 if (pi == nn_pad_map.end()) {
876 Pad* pad = pi->second;
878 if (pad->do_when_pressed == Pad::FlashOn) {
879 pad->set_color (LED::White);
880 pad->set_state (LED::OneShot24th);
881 write (pad->state_msg());
882 } else if (pad->do_when_pressed == Pad::FlashOff) {
883 pad->set_color (LED::Black);
884 pad->set_state (LED::OneShot24th);
885 write (pad->state_msg());
890 Push2::handle_midi_note_off_message (MIDI::Parser&, MIDI::EventTwoBytes* ev)
892 DEBUG_TRACE (DEBUG::Push2, string_compose ("Note Off %1 (velocity %2)\n", (int) ev->note_number, (int) ev->velocity));
894 if (ev->note_number < 11) {
895 /* theoretically related to encoder touch start/end, but
896 * actually they send note on with two different velocity
902 NNPadMap::iterator pi = nn_pad_map.find (ev->note_number);
904 if (pi == nn_pad_map.end()) {
908 Pad* pad = pi->second;
910 if (pad->do_when_pressed == Pad::FlashOn) {
911 pad->set_color (LED::Black);
912 pad->set_state (LED::OneShot24th);
913 write (pad->state_msg());
914 } else if (pad->do_when_pressed == Pad::FlashOff) {
915 pad->set_color (pad->perma_color);
916 pad->set_state (LED::OneShot24th);
917 write (pad->state_msg());
922 Push2::handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t pb)
927 Push2::thread_init ()
929 struct sched_param rtparam;
931 pthread_set_name (event_loop_name().c_str());
933 PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048);
934 ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128);
936 memset (&rtparam, 0, sizeof (rtparam));
937 rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
939 if (pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam) != 0) {
940 // do we care? not particularly.
945 Push2::connect_session_signals()
947 // receive routes added
948 //session->RouteAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&MackieControlProtocol::notify_routes_added, this, _1), this);
949 // receive VCAs added
950 //session->vca_manager().VCAAdded.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_vca_added, this, _1), this);
952 // receive record state toggled
953 session->RecordStateChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_record_state_changed, this), this);
954 // receive transport state changed
955 session->TransportStateChange.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_transport_state_changed, this), this);
956 session->TransportLooped.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_loop_state_changed, this), this);
957 // receive punch-in and punch-out
958 Config->ParameterChanged.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_parameter_changed, this, _1), this);
959 session->config.ParameterChanged.connect (session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_parameter_changed, this, _1), this);
960 // receive rude solo changed
961 session->SoloActive.connect(session_connections, MISSING_INVALIDATOR, boost::bind (&Push2::notify_solo_active_changed, this, _1), this);
965 Push2::notify_record_state_changed ()
967 IDButtonMap::iterator b = id_button_map.find (RecordEnable);
969 if (b == id_button_map.end()) {
973 switch (session->record_status ()) {
974 case Session::Disabled:
975 b->second->set_color (LED::White);
976 b->second->set_state (LED::NoTransition);
978 case Session::Enabled:
979 b->second->set_color (LED::Red);
980 b->second->set_state (LED::Blinking4th);
982 case Session::Recording:
983 b->second->set_color (LED::Red);
984 b->second->set_state (LED::OneShot24th);
988 write (b->second->state_msg());
992 Push2::notify_transport_state_changed ()
994 Button* b = id_button_map[Play];
996 if (session->transport_rolling()) {
997 b->set_state (LED::OneShot24th);
998 b->set_color (LED::Green);
1001 /* disable any blink on FixedLength from pending edit range op */
1002 Button* fl = id_button_map[FixedLength];
1004 fl->set_color (LED::Black);
1005 fl->set_state (LED::NoTransition);
1006 write (fl->state_msg());
1008 b->set_color (LED::White);
1009 b->set_state (LED::NoTransition);
1012 write (b->state_msg());
1016 Push2::notify_loop_state_changed ()
1021 Push2::notify_parameter_changed (std::string param)
1023 IDButtonMap::iterator b;
1025 if (param == "clicking") {
1026 if ((b = id_button_map.find (Metronome)) == id_button_map.end()) {
1029 if (Config->get_clicking()) {
1030 b->second->set_state (LED::Blinking4th);
1031 b->second->set_color (LED::White);
1033 b->second->set_color (LED::White);
1034 b->second->set_state (LED::NoTransition);
1036 write (b->second->state_msg ());
1041 Push2::notify_solo_active_changed (bool yn)
1043 IDButtonMap::iterator b = id_button_map.find (Solo);
1045 if (b == id_button_map.end()) {
1050 b->second->set_state (LED::Blinking4th);
1051 b->second->set_color (LED::Red);
1053 b->second->set_state (LED::NoTransition);
1054 b->second->set_color (LED::White);
1057 write (b->second->state_msg());
1063 XMLNode& node (ControlProtocol::get_state());
1066 child = new XMLNode (X_("Input"));
1067 child->add_child_nocopy (_async_in->get_state());
1068 node.add_child_nocopy (*child);
1069 child = new XMLNode (X_("Output"));
1070 child->add_child_nocopy (_async_out->get_state());
1071 node.add_child_nocopy (*child);
1073 node.add_property (X_("root"), to_string (_scale_root, std::dec));
1074 node.add_property (X_("root_octave"), to_string (_root_octave, std::dec));
1075 node.add_property (X_("in_key"), _in_key ? X_("yes") : X_("no"));
1076 node.add_property (X_("mode"), enum_2_string (_mode));
1082 Push2::set_state (const XMLNode & node, int version)
1084 DEBUG_TRACE (DEBUG::Push2, string_compose ("Push2::set_state: active %1\n", active()));
1088 if (ControlProtocol::set_state (node, version)) {
1094 if ((child = node.child (X_("Input"))) != 0) {
1095 XMLNode* portnode = child->child (Port::state_node_name.c_str());
1097 _async_in->set_state (*portnode, version);
1101 if ((child = node.child (X_("Output"))) != 0) {
1102 XMLNode* portnode = child->child (Port::state_node_name.c_str());
1104 _async_out->set_state (*portnode, version);
1108 XMLProperty const* prop;
1110 if ((prop = node.property (X_("root"))) != 0) {
1111 _scale_root = atoi (prop->value());
1114 if ((prop = node.property (X_("root_octave"))) != 0) {
1115 _root_octave = atoi (prop->value());
1118 if ((prop = node.property (X_("in_key"))) != 0) {
1119 _in_key = string_is_affirmative (prop->value());
1122 if ((prop = node.property (X_("mode"))) != 0) {
1123 _mode = (MusicalMode::Type) string_2_enum (prop->value(), _mode);
1130 Push2::other_vpot (int n, int delta)
1138 /* master gain control */
1140 boost::shared_ptr<AutomationControl> ac = master->gain_control();
1142 ac->set_value (ac->get_value() + ((2.0/64.0) * delta), PBD::Controllable::UseGroup);
1150 Push2::other_vpot_touch (int n, bool touching)
1159 boost::shared_ptr<AutomationControl> ac = master->gain_control();
1162 ac->start_touch (session->audible_frame());
1164 ac->stop_touch (true, session->audible_frame());
1172 Push2::start_shift ()
1174 cerr << "start shift\n";
1175 _modifier_state = ModifierState (_modifier_state | ModShift);
1176 Button* b = id_button_map[Shift];
1177 b->set_color (LED::White);
1178 b->set_state (LED::Blinking16th);
1179 write (b->state_msg());
1185 if (_modifier_state & ModShift) {
1186 cerr << "end shift\n";
1187 _modifier_state = ModifierState (_modifier_state & ~(ModShift));
1188 Button* b = id_button_map[Shift];
1189 b->timeout_connection.disconnect ();
1190 b->set_color (LED::White);
1191 b->set_state (LED::OneShot24th);
1192 write (b->state_msg());
1199 std::string splash_file;
1201 Searchpath rc (ARDOUR::ardour_data_search_path());
1202 rc.add_subdirectory_to_paths ("resources");
1204 if (!find_file (rc, PROGRAM_NAME "-splash.png", splash_file)) {
1205 cerr << "Cannot find splash screen image file\n";
1206 throw failed_constructor();
1209 Cairo::RefPtr<Cairo::ImageSurface> img = Cairo::ImageSurface::create_from_png (splash_file);
1211 double x_ratio = (double) img->get_width() / (cols - 20);
1212 double y_ratio = (double) img->get_height() / (rows - 20);
1213 double scale = min (x_ratio, y_ratio);
1217 context->set_source_rgb (0.764, 0.882, 0.882);
1223 context->translate (5, 5);
1224 context->scale (scale, scale);
1225 context->set_source (img, 0, 0);
1227 context->restore ();
1231 Glib::RefPtr<Pango::Layout> some_text = Pango::Layout::create (context);
1233 Pango::FontDescription fd ("Sans 38");
1234 some_text->set_font_description (fd);
1235 some_text->set_text (string_compose ("%1 %2", PROGRAM_NAME, VERSIONSTRING));
1237 context->move_to (200, 10);
1238 context->set_source_rgb (0, 0, 0);
1239 some_text->update_from_cairo_context (context);
1240 some_text->show_in_cairo_context (context);
1242 Pango::FontDescription fd2 ("Sans Italic 18");
1243 some_text->set_font_description (fd2);
1244 some_text->set_text (_("Ableton Push 2 Support"));
1246 context->move_to (200, 80);
1247 context->set_source_rgb (0, 0, 0);
1248 some_text->update_from_cairo_context (context);
1249 some_text->show_in_cairo_context (context);
1251 splash_start = get_microseconds ();
1252 blit_to_device_frame_buffer ();
1256 Push2::pad_filter (MidiBuffer& in, MidiBuffer& out) const
1258 /* This filter is called asynchronously from a realtime process
1259 context. It must use atomics to check state, and must not block.
1262 bool matched = false;
1264 for (MidiBuffer::iterator ev = in.begin(); ev != in.end(); ++ev) {
1265 if ((*ev).is_note_on() || (*ev).is_note_off()) {
1267 /* encoder touch start/touch end use note
1268 * 0-10. touchstrip uses note 12
1271 if ((*ev).note() > 10 && (*ev).note() != 12) {
1273 const int n = (*ev).note ();
1274 NNPadMap::const_iterator nni = nn_pad_map.find (n);
1276 if (nni != nn_pad_map.end()) {
1277 Pad const * pad = nni->second;
1278 /* shift for output to the shadow port */
1279 if (pad->filtered >= 0) {
1280 (*ev).set_note (pad->filtered + (octave_shift*12));
1281 out.push_back (*ev);
1282 /* shift back so that the pads light correctly */
1285 /* no mapping, don't send event */
1288 out.push_back (*ev);
1293 } else if ((*ev).is_pitch_bender() || (*ev).is_aftertouch() || (*ev).is_channel_pressure()) {
1294 out.push_back (*ev);
1302 Push2::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
1304 DEBUG_TRACE (DEBUG::FaderPort, "FaderPort::connection_handler start\n");
1305 if (!_input_port || !_output_port) {
1309 string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_async_in)->name());
1310 string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_async_out)->name());
1312 if (ni == name1 || ni == name2) {
1314 connection_state |= InputConnected;
1316 connection_state &= ~InputConnected;
1318 } else if (no == name1 || no == name2) {
1320 connection_state |= OutputConnected;
1322 connection_state &= ~OutputConnected;
1325 DEBUG_TRACE (DEBUG::FaderPort, string_compose ("Connections between %1 and %2 changed, but I ignored it\n", name1, name2));
1330 if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
1332 /* XXX this is a horrible hack. Without a short sleep here,
1333 something prevents the device wakeup messages from being
1334 sent and/or the responses from being received.
1338 DEBUG_TRACE (DEBUG::FaderPort, "device now connected for both input and output\n");
1342 DEBUG_TRACE (DEBUG::FaderPort, "Device disconnected (input or output or both) or not yet fully connected\n");
1345 ConnectionChange (); /* emit signal for our GUI */
1347 DEBUG_TRACE (DEBUG::FaderPort, "FaderPort::connection_handler end\n");
1349 return true; /* connection status changed */
1352 boost::shared_ptr<Port>
1353 Push2::output_port()
1358 boost::shared_ptr<Port>
1365 Push2::pad_note (int row, int col) const
1367 NNPadMap::const_iterator nni = nn_pad_map.find (36+(row*8)+col);
1369 if (nni != nn_pad_map.end()) {
1370 return nni->second->filtered;
1377 Push2::set_pad_scale (int root, int octave, MusicalMode::Type mode, bool inkey)
1379 MusicalMode m (mode);
1380 vector<float>::iterator interval;
1382 const int original_root = root;
1384 interval = m.steps.begin();
1385 root += (octave*12);
1388 const int root_start = root;
1390 set<int> mode_map; /* contains only notes in mode, O(logN) lookup */
1391 vector<int> mode_vector; /* sorted in note order */
1393 mode_map.insert (note);
1394 mode_vector.push_back (note);
1396 /* build a map of all notes in the mode, from the root to 127 */
1398 while (note < 128) {
1400 if (interval == m.steps.end()) {
1402 /* last distance was the end of the scale,
1403 so wrap, adding the next note at one
1404 octave above the last root.
1407 interval = m.steps.begin();
1409 mode_map.insert (root);
1410 mode_vector.push_back (root);
1413 note = (int) floor (root + (2.0 * (*interval)));
1415 mode_map.insert (note);
1416 mode_vector.push_back (note);
1422 vector<int>::iterator notei;
1424 for (int row = 0; row < 8; ++row) {
1426 /* Ableton's grid layout wraps the available notes in the scale
1427 * by offsetting 3 notes per row (from the bottom)
1430 notei = mode_vector.begin();
1431 notei += row_offset;
1434 for (int col = 0; col < 8; ++col) {
1435 int index = 36 + (row*8) + col;
1436 Pad* pad = nn_pad_map[index];
1438 if (notei != mode_vector.end()) {
1441 pad->filtered = notenum;
1443 if ((notenum % 12) == original_root) {
1444 pad->set_color (LED::Green);
1445 pad->perma_color = LED::Green;
1447 pad->set_color (LED::White);
1448 pad->perma_color = LED::White;
1451 pad->do_when_pressed = Pad::FlashOff;
1456 pad->set_color (LED::Black);
1457 pad->do_when_pressed = Pad::Nothing;
1461 write (pad->state_msg());
1467 /* chromatic: all notes available, but highlight those in the scale */
1469 for (note = 36; note < 100; ++note) {
1471 Pad* pad = nn_pad_map[note];
1473 /* Chromatic: all pads play, half-tone steps. Light
1474 * those in the scale, and highlight root notes
1477 pad->filtered = root_start + (note - 36);
1479 if (mode_map.find (note) != mode_map.end()) {
1481 if ((note % 12) == original_root) {
1482 pad->set_color (LED::Green);
1483 pad->perma_color = LED::Green;
1485 pad->set_color (LED::White);
1486 pad->perma_color = LED::White;
1489 pad->do_when_pressed = Pad::FlashOff;
1493 /* note is not in mode, turn it off */
1495 pad->do_when_pressed = Pad::FlashOn;
1496 pad->set_color (LED::Black);
1500 write (pad->state_msg());
1504 PadChange (); /* EMIT SIGNAL */
1508 _scale_root = original_root;
1509 _root_octave = octave;
1515 Push2::set_percussive_mode (bool yn)
1518 cerr << "back to scale\n";
1519 set_pad_scale (_scale_root, _root_octave, _mode, _in_key);
1526 for (int row = 0; row < 8; ++row) {
1528 for (int col = 0; col < 4; ++col) {
1530 int index = 36 + (row*8) + col;
1531 Pad* pad = nn_pad_map[index];
1533 pad->filtered = drum_note;
1538 for (int row = 0; row < 8; ++row) {
1540 for (int col = 4; col < 8; ++col) {
1542 int index = 36 + (row*8) + col;
1543 Pad* pad = nn_pad_map[index];
1545 pad->filtered = drum_note;
1552 PadChange (); /* EMIT SIGNAL */
1556 Push2::current_layout () const
1558 Glib::Threads::Mutex::Lock lm (layout_lock);
1559 return _current_layout;
1563 Push2::stripable_selection_change (StripableNotificationListPtr selected)
1565 boost::shared_ptr<MidiPort> pad_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in)->shadow_port();
1566 boost::shared_ptr<MidiTrack> current_midi_track = current_pad_target.lock();
1567 boost::shared_ptr<MidiTrack> new_pad_target;
1569 /* See if there's a MIDI track selected */
1571 for (StripableNotificationList::iterator si = selected->begin(); si != selected->end(); ++si) {
1573 new_pad_target = boost::dynamic_pointer_cast<MidiTrack> ((*si).lock());
1575 if (new_pad_target) {
1580 if (new_pad_target) {
1581 cerr << "new midi pad target " << new_pad_target->name() << endl;
1583 cerr << "no midi pad target\n";
1586 if (current_midi_track == new_pad_target) {
1591 if (!new_pad_target) {
1592 /* leave existing connection alone */
1596 /* disconnect from pad port, if appropriate */
1598 if (current_midi_track && pad_port) {
1599 cerr << "Disconnect pads from " << current_midi_track->name() << endl;
1600 current_midi_track->input()->disconnect (current_midi_track->input()->nth(0), pad_port->name(), this);
1603 /* now connect the pad port to this (newly) selected midi
1604 * track, if indeed there is one.
1607 if (new_pad_target && pad_port) {
1608 cerr << "Reconnect pads to " << new_pad_target->name() << endl;
1609 new_pad_target->input()->connect (new_pad_target->input()->nth (0), pad_port->name(), this);
1610 current_pad_target = new_pad_target;
1612 current_pad_target.reset ();
1617 Push2::button_by_id (ButtonID bid)
1619 return id_button_map[bid];
1623 Push2::get_color_index (uint32_t rgb)
1625 ColorMap::iterator i = color_map.find (rgb);
1627 if (i != color_map.end()) {
1632 UINT_TO_RGBA (rgb, &r, &g, &b, &a);
1633 int w = 204; /* not sure where/when we should get this value */
1635 /* get a free index */
1639 if (color_map_free_list.empty()) {
1640 /* random replacement of any entry above zero and below 122 (where the
1641 * Ableton standard colors live)
1643 index = 1 + (random() % 121);
1645 index = color_map_free_list.top();
1646 color_map_free_list.pop();
1649 MidiByteArray palette_msg (17, 0xf0, 0x00 , 0x21, 0x1d, 0x01, 0x01, 0x03, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x01, 0x7E, 0x00, 0xF7);
1650 MidiByteArray update_pallette_msg (8, 0xf0, 0x00, 0x21, 0x1d, 0x01, 0x01, 0x05, 0xF7);
1652 palette_msg[7] = index;
1653 palette_msg[8] = r & 0x7f;
1654 palette_msg[9] = r & 0x1;
1655 palette_msg[10] = g & 0x7f;
1656 palette_msg[11] = g & 0x1;
1657 palette_msg[12] = b & 0x7f;
1658 palette_msg[13] = b & 0x1;
1659 palette_msg[14] = w & 0x7f;
1660 palette_msg[15] = w & 0x1;
1662 write (palette_msg);
1663 write (update_pallette_msg);
1665 color_map[index] = rgb;
1671 Push2::build_color_map ()
1673 /* These are "standard" colors that Ableton docs suggest will always be
1674 there. Put them in our color map so that when we look up these
1675 colors, we will use the Ableton indices for them.
1678 color_map.insert (make_pair (RGB_TO_UINT (0,0,0), 0));
1679 color_map.insert (make_pair (RGB_TO_UINT (204,204,204), 122));
1680 color_map.insert (make_pair (RGB_TO_UINT (64,64,64), 123));
1681 color_map.insert (make_pair (RGB_TO_UINT (20,20,20), 124));
1682 color_map.insert (make_pair (RGB_TO_UINT (0,0,255), 125));
1683 color_map.insert (make_pair (RGB_TO_UINT (0,255,0), 126));
1684 color_map.insert (make_pair (RGB_TO_UINT (255,0,0), 127));
1686 for (uint8_t n = 1; n < 122; ++n) {
1687 color_map_free_list.push (n);
1692 Push2::fill_color_table ()
1694 colors.insert (make_pair (DarkBackground, ArdourCanvas::rgba_to_color (0, 0, 0, 1)));
1695 colors.insert (make_pair (LightBackground, ArdourCanvas::rgba_to_color (0.98, 0.98, 0.98, 1)));
1697 colors.insert (make_pair (ParameterName, ArdourCanvas::rgba_to_color (0.98, 0.98, 0.98, 1)));
1699 colors.insert (make_pair (KnobArcBackground, ArdourCanvas::rgba_to_color (0.3, 0.3, 0.3, 1.0)));
1700 colors.insert (make_pair (KnobArcStart, ArdourCanvas::rgba_to_color (1.0, 0.0, 0.0, 1.0)));
1701 colors.insert (make_pair (KnobArcEnd, ArdourCanvas::rgba_to_color (0.0, 1.0, 0.0, 1.0)));
1703 colors.insert (make_pair (KnobLineShadow, ArdourCanvas::rgba_to_color (0, 0, 0, 0.3)));
1704 colors.insert (make_pair (KnobLine, ArdourCanvas::rgba_to_color (1, 1, 1, 1)));
1706 colors.insert (make_pair (KnobForeground, ArdourCanvas::rgba_to_color (0.2, 0.2, 0.2, 1)));
1707 colors.insert (make_pair (KnobBackground, ArdourCanvas::rgba_to_color (0.2, 0.2, 0.2, 1)));
1708 colors.insert (make_pair (KnobShadow, ArdourCanvas::rgba_to_color (0, 0, 0, 0.1)));
1709 colors.insert (make_pair (KnobBorder, ArdourCanvas::rgba_to_color (0, 0, 0, 1)));
1714 Push2::get_color (ColorName name)
1716 Colors::iterator c = colors.find (name);
1717 if (c != colors.end()) {
1725 Push2::set_current_layout (Push2Layout* layout)
1727 if (_current_layout) {
1728 _current_layout->on_hide ();
1731 _current_layout = layout;
1734 if (_current_layout) {
1735 _current_layout->on_show ();