add new debug bit for backend callbacks
[ardour.git] / libs / ardour / session_midi.cc
1 /*
2  * Copyright (C) 2005-2009 Taybin Rutkin <taybin@taybin.com>
3  * Copyright (C) 2005-2019 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2006-2012 David Robillard <d@drobilla.net>
5  * Copyright (C) 2008 Hans Baier <hansfbaier@googlemail.com>
6  * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
7  * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
8  * Copyright (C) 2013 John Emmas <john@creativepost.co.uk>
9  * Copyright (C) 2013 Michael Fisher <mfisher31@gmail.com>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include <string>
27 #include <cmath>
28 #include <cerrno>
29 #include <cassert>
30 #include <unistd.h>
31
32 #include <boost/shared_ptr.hpp>
33
34 #include <glibmm/main.h>
35
36 #include "midi++/mmc.h"
37 #include "midi++/port.h"
38
39 #include "pbd/error.h"
40 #include "pbd/pthread_utils.h"
41 #include "pbd/timersub.h"
42 #include "pbd/stacktrace.h"
43
44 #include "temporal/time.h"
45
46 #include "ardour/audio_track.h"
47 #include "ardour/audioengine.h"
48 #include "ardour/debug.h"
49 #include "ardour/midi_port.h"
50 #include "ardour/midi_track.h"
51 #include "ardour/midi_ui.h"
52 #include "ardour/profile.h"
53 #include "ardour/session.h"
54 #include "ardour/transport_master.h"
55 #include "ardour/ticker.h"
56
57 #include "pbd/i18n.h"
58
59 using namespace std;
60 using namespace ARDOUR;
61 using namespace PBD;
62 using namespace MIDI;
63 using namespace Glib;
64
65 void
66 Session::midi_panic()
67 {
68         {
69                 boost::shared_ptr<RouteList> r = routes.reader ();
70
71                 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
72                         MidiTrack *track = dynamic_cast<MidiTrack*>((*i).get());
73                         if (track != 0) {
74                                 track->midi_panic();
75                         }
76                 }
77         }
78 }
79
80 void
81 Session::setup_midi_control ()
82 {
83         outbound_mtc_timecode_frame = 0;
84         next_quarter_frame_to_send = 0;
85
86         /* Set up the qtr frame message */
87
88         mtc_msg[0] = 0xf1;
89         mtc_msg[2] = 0xf1;
90         mtc_msg[4] = 0xf1;
91         mtc_msg[6] = 0xf1;
92         mtc_msg[8] = 0xf1;
93         mtc_msg[10] = 0xf1;
94         mtc_msg[12] = 0xf1;
95         mtc_msg[14] = 0xf1;
96 }
97
98 void
99 Session::spp_start ()
100 {
101         if (Config->get_mmc_control ()) {
102                 request_transport_speed (1.0);
103         }
104 }
105
106 void
107 Session::spp_continue ()
108 {
109         spp_start ();
110 }
111
112 void
113 Session::spp_stop ()
114 {
115         if (Config->get_mmc_control ()) {
116                 request_stop ();
117         }
118 }
119
120 void
121 Session::mmc_deferred_play (MIDI::MachineControl &/*mmc*/)
122 {
123         if (Config->get_mmc_control ()) {
124                 request_transport_speed (1.0);
125         }
126 }
127
128 void
129 Session::mmc_record_pause (MIDI::MachineControl &/*mmc*/)
130 {
131         if (Config->get_mmc_control ()) {
132                 maybe_enable_record();
133         }
134 }
135
136 void
137 Session::mmc_record_strobe (MIDI::MachineControl &/*mmc*/)
138 {
139         if (!Config->get_mmc_control() || (_step_editors > 0)) {
140                 return;
141         }
142
143         /* record strobe does an implicit "Play" command */
144
145         if (_transport_speed != 1.0) {
146
147                 /* start_transport() will move from Enabled->Recording, so we
148                    don't need to do anything here except enable recording.
149                    its not the same as maybe_enable_record() though, because
150                    that *can* switch to Recording, which we do not want.
151                 */
152
153                 save_state ("", true);
154                 g_atomic_int_set (&_record_status, Enabled);
155                 RecordStateChanged (); /* EMIT SIGNAL */
156
157                 request_transport_speed (1.0);
158
159         } else {
160
161                 enable_record ();
162         }
163 }
164
165 void
166 Session::mmc_record_exit (MIDI::MachineControl &/*mmc*/)
167 {
168         if (Config->get_mmc_control ()) {
169                 disable_record (false);
170         }
171 }
172
173 void
174 Session::mmc_stop (MIDI::MachineControl &/*mmc*/)
175 {
176         if (Config->get_mmc_control ()) {
177                 request_stop ();
178         }
179 }
180
181 void
182 Session::mmc_pause (MIDI::MachineControl &/*mmc*/)
183 {
184         if (Config->get_mmc_control ()) {
185
186                 /* We support RECORD_PAUSE, so the spec says that
187                    we must interpret PAUSE like RECORD_PAUSE if
188                    recording.
189                 */
190
191                 if (actively_recording()) {
192                         maybe_enable_record ();
193                 } else {
194                         request_stop ();
195                 }
196         }
197 }
198
199 static bool step_queued = false;
200
201 void
202 Session::mmc_step (MIDI::MachineControl &/*mmc*/, int steps)
203 {
204         if (!Config->get_mmc_control ()) {
205                 return;
206         }
207
208         struct timeval now;
209         struct timeval diff = { 0, 0 };
210
211         gettimeofday (&now, 0);
212
213         timersub (&now, &last_mmc_step, &diff);
214
215         gettimeofday (&now, 0);
216         timersub (&now, &last_mmc_step, &diff);
217
218         if (last_mmc_step.tv_sec != 0 && (diff.tv_usec + (diff.tv_sec * 1000000)) < _engine.usecs_per_cycle()) {
219                 return;
220         }
221
222         double diff_secs = diff.tv_sec + (diff.tv_usec / 1000000.0);
223         double cur_speed = (((steps * 0.5) * timecode_frames_per_second()) / diff_secs) / timecode_frames_per_second();
224
225         if (_transport_speed == 0 || cur_speed * _transport_speed < 0) {
226                 /* change direction */
227                 step_speed = cur_speed;
228         } else {
229                 step_speed = (0.6 * step_speed) + (0.4 * cur_speed);
230         }
231
232         step_speed *= 0.25;
233
234 #if 0
235         cerr << "delta = " << diff_secs
236              << " ct = " << _transport_speed
237              << " steps = " << steps
238              << " new speed = " << cur_speed
239              << " speed = " << step_speed
240              << endl;
241 #endif
242
243         request_transport_speed_nonzero (step_speed);
244         last_mmc_step = now;
245
246         if (!step_queued) {
247                 if (midi_control_ui) {
248                         RefPtr<TimeoutSource> tsrc = TimeoutSource::create (100);
249                         tsrc->connect (sigc::mem_fun (*this, &Session::mmc_step_timeout));
250                         tsrc->attach (midi_control_ui->main_loop()->get_context());
251                         step_queued = true;
252                 }
253         }
254 }
255
256 void
257 Session::mmc_rewind (MIDI::MachineControl &/*mmc*/)
258 {
259         if (Config->get_mmc_control ()) {
260                 request_transport_speed(-8.0f);
261         }
262 }
263
264 void
265 Session::mmc_fast_forward (MIDI::MachineControl &/*mmc*/)
266 {
267         if (Config->get_mmc_control ()) {
268                 request_transport_speed(8.0f);
269         }
270 }
271
272 void
273 Session::mmc_locate (MIDI::MachineControl &/*mmc*/, const MIDI::byte* mmc_tc)
274 {
275         if (!Config->get_mmc_control ()) {
276                 return;
277         }
278
279         samplepos_t target_sample;
280         Timecode::Time timecode;
281
282         timecode.hours = mmc_tc[0] & 0xf;
283         timecode.minutes = mmc_tc[1];
284         timecode.seconds = mmc_tc[2];
285         timecode.frames = mmc_tc[3];
286         timecode.rate = timecode_frames_per_second();
287         timecode.drop = timecode_drop_frames();
288
289         // Also takes timecode offset into account:
290         timecode_to_sample( timecode, target_sample, true /* use_offset */, false /* use_subframes */ );
291
292         if (target_sample > max_samplepos) {
293                 target_sample = max_samplepos;
294         }
295
296         /* Some (all?) MTC/MMC devices do not send a full MTC frame
297            at the end of a locate, instead sending only an MMC
298            locate command. This causes the current position
299            of an MTC slave to become out of date. Catch this.
300         */
301
302         boost::shared_ptr<MTC_TransportMaster> mtcs = boost::dynamic_pointer_cast<MTC_TransportMaster> (transport_master());
303
304         if (mtcs) {
305                 // cerr << "Locate *with* MTC slave\n";
306                 mtcs->handle_locate (mmc_tc);
307         } else {
308                 // cerr << "Locate without MTC slave\n";
309                 request_locate (target_sample, false);
310         }
311 }
312
313 void
314 Session::mmc_shuttle (MIDI::MachineControl &/*mmc*/, float speed, bool forw)
315 {
316         if (!Config->get_mmc_control ()) {
317                 return;
318         }
319
320         if (Config->get_shuttle_speed_threshold() >= 0 && speed > Config->get_shuttle_speed_threshold()) {
321                 speed *= Config->get_shuttle_speed_factor();
322         }
323
324         if (forw) {
325                 request_transport_speed_nonzero (speed);
326         } else {
327                 request_transport_speed_nonzero (-speed);
328         }
329 }
330
331 boost::shared_ptr<Route>
332 Session::get_midi_nth_route_by_id (PresentationInfo::order_t n) const
333 {
334         PresentationInfo::Flag f;
335
336         /* These numbers are defined by the MMC specification.
337          */
338
339         if (n == 318) {
340                 f = PresentationInfo::MasterOut;
341         } else if (n == 319) {
342                 f = PresentationInfo::MonitorOut;
343         } else {
344                 f = PresentationInfo::Route;
345         }
346
347         boost::shared_ptr<RouteList> r = routes.reader ();
348         PresentationInfo::order_t match_cnt = 0;
349
350         for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
351                 if ((*i)->presentation_info().flag_match (f)) {
352                         if (match_cnt++ == n) {
353                                 return *i;
354                         }
355                 }
356         }
357
358         return boost::shared_ptr<Route>();
359 }
360
361 void
362 Session::mmc_record_enable (MIDI::MachineControl &mmc, size_t trk, bool enabled)
363 {
364         if (!Config->get_mmc_control ()) {
365                 return;
366         }
367
368         boost::shared_ptr<Route> r = get_midi_nth_route_by_id (trk);
369
370         if (r) {
371                 boost::shared_ptr<AudioTrack> at;
372
373                 if ((at = boost::dynamic_pointer_cast<AudioTrack> (r))) {
374                         at->rec_enable_control()->set_value (enabled, Controllable::UseGroup);
375                 }
376         }
377 }
378
379 /** Send MTC Full Frame message (complete Timecode time) for the start of this cycle.
380  * This resets the MTC code, the next quarter frame message that is sent will be
381  * the first one with the beginning of this cycle as the new start point.
382  * @param t time to send.
383  */
384 int
385 Session::send_full_time_code (samplepos_t const t, MIDI::pframes_t nframes)
386 {
387         /* This function could easily send at a given sample offset, but would
388          * that be useful?  Does ardour do sub-block accurate locating? [DR] */
389
390         MIDI::byte msg[10];
391         Timecode::Time timecode;
392
393         _send_timecode_update = false;
394
395         if (_engine.freewheeling() || !Config->get_send_mtc()) {
396                 return 0;
397         }
398
399         if (transport_master_is_external() && !transport_master()->locked()) {
400                 return 0;
401         }
402
403         // Get timecode time for the given time
404         sample_to_timecode (t, timecode, true /* use_offset */, false /* no subframes */);
405
406         // sample-align outbound to rounded (no subframes) timecode
407         samplepos_t mtc_tc;
408         timecode_to_sample(timecode, mtc_tc, true, false);
409         outbound_mtc_timecode_frame = mtc_tc;
410         transmitting_timecode_time = timecode;
411
412         LatencyRange mtc_out_latency = {0, 0}; // TODO cache this, update on engine().GraphReordered()
413         _midi_ports->mtc_output_port ()->get_connected_latency_range (ltc_out_latency, true);
414         sampleoffset_t mtc_offset = mtc_out_latency.max;
415
416         // only if rolling.. ?
417         outbound_mtc_timecode_frame += mtc_offset;
418
419         // outbound_mtc_timecode_frame needs to be >= _transport_sample
420         // or a new full timecode will be queued next cycle.
421         while (outbound_mtc_timecode_frame < t) {
422                 Timecode::increment (transmitting_timecode_time, config.get_subframes_per_frame());
423                 outbound_mtc_timecode_frame += _samples_per_timecode_frame;
424         }
425
426         double const quarter_frame_duration = ((samplecnt_t) _samples_per_timecode_frame) / 4.0;
427         if (ceil((t - mtc_tc) / quarter_frame_duration) > 0) {
428                 Timecode::increment (transmitting_timecode_time, config.get_subframes_per_frame());
429                 outbound_mtc_timecode_frame += _samples_per_timecode_frame;
430         }
431
432         DEBUG_TRACE (DEBUG::MTC, string_compose ("Full MTC TC %1 (off %2)\n", outbound_mtc_timecode_frame, mtc_offset));
433
434         /* according to MTC spec 24, 30 drop and 30 non-drop TC, the frame-number represented by 8 quarter frames must be even. */
435         if (((mtc_timecode_bits >> 5) != MIDI::MTC_25_FPS) && (transmitting_timecode_time.frames % 2)) {
436                 /* start MTC quarter frame transmission on an even frame */
437                 Timecode::increment (transmitting_timecode_time, config.get_subframes_per_frame());
438                 outbound_mtc_timecode_frame += _samples_per_timecode_frame;
439         }
440
441         next_quarter_frame_to_send = 0;
442
443         // Sync slave to the same Timecode time as we are on
444         msg[0] = 0xf0;
445         msg[1] = 0x7f;
446         msg[2] = 0x7f;
447         msg[3] = 0x1;
448         msg[4] = 0x1;
449         msg[9] = 0xf7;
450
451         msg[5] = mtc_timecode_bits | (timecode.hours % 24);
452         msg[6] = timecode.minutes;
453         msg[7] = timecode.seconds;
454         msg[8] = timecode.frames;
455
456         // Send message at offset 0, sent time is for the start of this cycle
457
458         MidiBuffer& mb (_midi_ports->mtc_output_port()->get_midi_buffer (nframes));
459         mb.push_back (Port::port_offset(), sizeof (msg), msg);
460
461         _pframes_since_last_mtc = 0;
462         return 0;
463 }
464
465 /** Send MTC (quarter-frame) messages for this cycle.
466  * Must be called exactly once per cycle from the process thread.  Realtime safe.
467  * This function assumes the state of full Timecode is sane, eg. the slave is
468  * expecting quarter frame messages and has the right frame of reference (any
469  * full MTC Timecode time messages that needed to be sent should have been sent
470  * earlier already this cycle by send_full_time_code)
471  */
472 int
473 Session::send_midi_time_code_for_cycle (samplepos_t start_sample, samplepos_t end_sample, ARDOUR::pframes_t nframes)
474 {
475         // start_sample == start_sample  for normal cycles
476         // start_sample > _transport_sample  for split cycles
477         if (_engine.freewheeling() || !_send_qf_mtc || transmitting_timecode_time.negative || (next_quarter_frame_to_send < 0)) {
478                 // cerr << "(MTC) Not sending MTC\n";
479                 return 0;
480         }
481         if (transport_master_is_external() && !transport_master()->locked()) {
482                 return 0;
483         }
484
485         if (_transport_speed < 0) {
486                 // we don't support rolling backwards
487                 return 0;
488         }
489
490         /* MTC is max. 30 fps - assert() below will fail
491          * TODO actually limit it to 24,25,29df,30fps
492          * talk to oofus, first.
493          */
494         if (Timecode::timecode_to_frames_per_second(config.get_timecode_format()) > 30) {
495                 return 0;
496         }
497
498         assert (next_quarter_frame_to_send >= 0);
499         assert (next_quarter_frame_to_send <= 7);
500
501         /* Duration of one quarter frame */
502         double const quarter_frame_duration = _samples_per_timecode_frame / 4.0;
503
504         DEBUG_TRACE (DEBUG::MTC, string_compose ("TF %1 SF %2 MT %3 QF %4 QD %5\n",
505                                                  _transport_sample, start_sample, outbound_mtc_timecode_frame,
506                                                  next_quarter_frame_to_send, quarter_frame_duration));
507
508         if (rint(outbound_mtc_timecode_frame + (next_quarter_frame_to_send * quarter_frame_duration)) < _transport_sample) {
509                 // send full timecode and set outbound_mtc_timecode_frame, next_quarter_frame_to_send
510                 send_full_time_code (_transport_sample, nframes);
511         }
512
513         if (rint(outbound_mtc_timecode_frame + (next_quarter_frame_to_send * quarter_frame_duration)) < start_sample) {
514                 // no QF for this cycle
515                 return 0;
516         }
517
518         /* Send quarter frames for this cycle */
519         while (end_sample > rint(outbound_mtc_timecode_frame + (next_quarter_frame_to_send * quarter_frame_duration))) {
520
521                 DEBUG_TRACE (DEBUG::MTC, string_compose ("next sample to send: %1\n", next_quarter_frame_to_send));
522
523                 switch (next_quarter_frame_to_send) {
524                 case 0:
525                         mtc_msg[1] = 0x00 | (transmitting_timecode_time.frames & 0xf);
526                         break;
527                 case 1:
528                         mtc_msg[1] = 0x10 | ((transmitting_timecode_time.frames & 0xf0) >> 4);
529                         break;
530                 case 2:
531                         mtc_msg[1] = 0x20 | (transmitting_timecode_time.seconds & 0xf);
532                         break;
533                 case 3:
534                         mtc_msg[1] = 0x30 | ((transmitting_timecode_time.seconds & 0xf0) >> 4);
535                         break;
536                 case 4:
537                         mtc_msg[1] = 0x40 | (transmitting_timecode_time.minutes & 0xf);
538                         break;
539                 case 5:
540                         mtc_msg[1] = 0x50 | ((transmitting_timecode_time.minutes & 0xf0) >> 4);
541                         break;
542                 case 6:
543                         mtc_msg[1] = 0x60 | ((mtc_timecode_bits | transmitting_timecode_time.hours) & 0xf);
544                         break;
545                 case 7:
546                         mtc_msg[1] = 0x70 | (((mtc_timecode_bits | transmitting_timecode_time.hours) & 0xf0) >> 4);
547                         break;
548                 }
549
550                 const samplepos_t msg_time = rint (outbound_mtc_timecode_frame + (quarter_frame_duration * next_quarter_frame_to_send));
551
552                 // This message must fall within this block or something is broken
553                 assert (msg_time >= start_sample);
554                 assert (msg_time < end_sample);
555
556                 /* convert from session samples back to JACK samples using the transport speed */
557                 ARDOUR::pframes_t const out_stamp = (msg_time - start_sample) / _transport_speed;
558                 assert (out_stamp < nframes);
559
560                 MidiBuffer& mb (_midi_ports->mtc_output_port()->get_midi_buffer(nframes));
561                 if (!mb.push_back (out_stamp, 2, mtc_msg)) {
562                         error << string_compose(_("Session: cannot send quarter-frame MTC message (%1)"), strerror (errno))
563                               << endmsg;
564                         return -1;
565                 }
566
567 #ifndef NDEBUG
568                 if (DEBUG_ENABLED(DEBUG::MTC)) {
569                         DEBUG_STR_DECL(foo);
570                         DEBUG_STR_APPEND(foo,"sending ");
571                         DEBUG_STR_APPEND(foo, transmitting_timecode_time);
572                         DEBUG_TRACE (DEBUG::MTC, string_compose ("%1 qfm = %2, stamp = %3\n", DEBUG_STR(foo).str(), next_quarter_frame_to_send,
573                                                                  out_stamp));
574                 }
575 #endif
576
577                 // Increment quarter frame counter
578                 next_quarter_frame_to_send++;
579
580                 if (next_quarter_frame_to_send >= 8) {
581                         // Wrap quarter frame counter
582                         next_quarter_frame_to_send = 0;
583                         // Increment timecode time twice
584                         Timecode::increment (transmitting_timecode_time, config.get_subframes_per_frame());
585                         Timecode::increment (transmitting_timecode_time, config.get_subframes_per_frame());
586                         // Increment timing of first quarter frame
587                         outbound_mtc_timecode_frame += 2.0 * _samples_per_timecode_frame;
588                 }
589         }
590
591         return 0;
592 }
593
594 /***********************************************************************
595  OUTBOUND MMC STUFF
596 **********************************************************************/
597
598 void
599 Session::send_immediate_mmc (MachineControlCommand c)
600 {
601         if (AudioEngine::instance()->in_process_thread()) {
602                 _mmc->send (c, Port::port_offset());
603         } else {
604                 _mmc->send (c, 0);
605         }
606
607 }
608
609 bool
610 Session::mmc_step_timeout ()
611 {
612         struct timeval now;
613         struct timeval diff;
614         double diff_usecs;
615         gettimeofday (&now, 0);
616
617         timersub (&now, &last_mmc_step, &diff);
618         diff_usecs = diff.tv_sec * 1000000 + diff.tv_usec;
619
620         if (diff_usecs > 1000000.0 || fabs (_transport_speed) < 0.0000001) {
621                 /* too long or too slow, stop transport */
622                 request_transport_speed (0.0);
623                 step_queued = false;
624                 return false;
625         }
626
627         if (diff_usecs < 250000.0) {
628                 /* too short, just keep going */
629                 return true;
630         }
631
632         /* slow it down */
633
634         request_transport_speed_nonzero (_transport_speed * 0.75);
635         return true;
636 }
637
638 /* *********************************************************************
639  * OUTBOUND SYSTEM COMMON STUFF
640  **********************************************************************/
641
642 void
643 Session::send_song_position_pointer (samplepos_t)
644 {
645         if (midi_clock) {
646                 /* Do nothing for the moment */
647         }
648 }
649
650 int
651 Session::start_midi_thread ()
652 {
653         if (midi_control_ui) { return 0; }
654         midi_control_ui = new MidiControlUI (*this);
655         midi_control_ui->run ();
656         return 0;
657 }
658
659 boost::shared_ptr<ARDOUR::Port>
660 Session::midi_input_port () const
661 {
662         return _midi_ports->midi_input_port ();
663 }
664
665 boost::shared_ptr<ARDOUR::Port>
666 Session::midi_output_port () const
667 {
668         return _midi_ports->midi_output_port ();
669 }
670
671 boost::shared_ptr<ARDOUR::Port>
672 Session::mmc_output_port () const
673 {
674         return _midi_ports->mmc_output_port ();
675 }
676
677 boost::shared_ptr<ARDOUR::Port>
678 Session::mmc_input_port () const
679 {
680         return _midi_ports->mmc_input_port ();
681 }
682
683 boost::shared_ptr<ARDOUR::Port>
684 Session::scene_output_port () const
685 {
686         return _midi_ports->scene_output_port ();
687 }
688
689 boost::shared_ptr<ARDOUR::Port>
690 Session::scene_input_port () const
691 {
692         return _midi_ports->scene_input_port ();
693 }
694
695 boost::shared_ptr<AsyncMIDIPort>
696 Session::vkbd_output_port () const
697 {
698         return _midi_ports->vkbd_output_port ();
699 }
700
701 boost::shared_ptr<MidiPort>
702 Session::midi_clock_output_port () const
703 {
704         return _midi_ports->midi_clock_output_port ();
705 }
706
707 boost::shared_ptr<MidiPort>
708 Session::mtc_output_port () const
709 {
710         return _midi_ports->mtc_output_port ();
711 }
712
713 void
714 Session::midi_track_presentation_info_changed (PropertyChange const& what_changed, boost::weak_ptr<MidiTrack> mt)
715 {
716         if (!Config->get_midi_input_follows_selection()) {
717                 return;
718         }
719
720         if (!what_changed.contains (Properties::selected)) {
721                 return;
722         }
723
724         boost::shared_ptr<MidiTrack> new_midi_target (mt.lock ());
725
726         if (new_midi_target->is_selected()) {
727                 rewire_selected_midi (new_midi_target);
728         }
729 }
730
731 void
732 Session::rewire_selected_midi (boost::shared_ptr<MidiTrack> new_midi_target)
733 {
734         if (!new_midi_target) {
735                 return;
736         }
737
738         boost::shared_ptr<MidiTrack> old_midi_target = current_midi_target.lock ();
739
740         if (new_midi_target == old_midi_target) {
741                 return;
742         }
743
744         vector<string> msp;
745         AudioEngine::instance()->get_midi_selection_ports (msp);
746
747         if (!msp.empty()) {
748
749                 if (old_midi_target) {
750                         old_midi_target->input()->disconnect (this);
751                 }
752
753                 for (vector<string>::const_iterator p = msp.begin(); p != msp.end(); ++p) {
754                         PortManager::MidiPortInformation mpi (AudioEngine::instance()->midi_port_information (*p));
755
756                         /* if a port is marked for control data, do not
757                          * disconnect it from everything since it may also be
758                          * used via a control surface or some other
759                          * functionality.
760                          */
761
762                         if (!(mpi.properties & MidiPortControl)) {
763                                 /* disconnect the port from everything */
764                                 AudioEngine::instance()->disconnect (*p);
765                         }
766                         /* connect it to the new target */
767                         new_midi_target->input()->connect (new_midi_target->input()->nth(0), (*p), this);
768                 }
769         }
770
771         current_midi_target = new_midi_target;
772 }
773
774 void
775 Session::rewire_midi_selection_ports ()
776 {
777         if (!Config->get_midi_input_follows_selection()) {
778                 return;
779         }
780
781         boost::shared_ptr<MidiTrack> target = current_midi_target.lock();
782
783         if (!target) {
784                 return;
785         }
786
787         vector<string> msp;
788         AudioEngine::instance()->get_midi_selection_ports (msp);
789
790         if (msp.empty()) {
791                 return;
792         }
793
794         target->input()->disconnect (this);
795
796         for (vector<string>::const_iterator p = msp.begin(); p != msp.end(); ++p) {
797                 AudioEngine::instance()->disconnect (*p);
798                 target->input()->connect (target->input()->nth (0), (*p), this);
799         }
800 }