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
43 #include "temporal/time.h"
44
45 #include "ardour/audio_track.h"
46 #include "ardour/audioengine.h"
47 #include "ardour/debug.h"
48 #include "ardour/midi_port.h"
49 #include "ardour/midi_track.h"
50 #include "ardour/midi_ui.h"
51 #include "ardour/profile.h"
52 #include "ardour/session.h"
53 #include "ardour/transport_master.h"
54 #include "ardour/transport_fsm.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
midi_panic()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
setup_midi_control()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
spp_start()99 Session::spp_start ()
100 {
101 if (Config->get_mmc_control ()) {
102 request_roll (TRS_MIDIClock);
103 }
104 }
105
106 void
spp_continue()107 Session::spp_continue ()
108 {
109 spp_start ();
110 }
111
112 void
spp_stop()113 Session::spp_stop ()
114 {
115 if (Config->get_mmc_control ()) {
116 request_stop ();
117 }
118 }
119
120 void
mmc_deferred_play(MIDI::MachineControl &)121 Session::mmc_deferred_play (MIDI::MachineControl &/*mmc*/)
122 {
123 if (Config->get_mmc_control ()) {
124 request_roll (TRS_MMC);
125 }
126 }
127
128 void
mmc_record_pause(MIDI::MachineControl &)129 Session::mmc_record_pause (MIDI::MachineControl &/*mmc*/)
130 {
131 if (Config->get_mmc_control ()) {
132 maybe_enable_record();
133 }
134 }
135
136 void
mmc_record_strobe(MIDI::MachineControl &)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_fsm->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_roll (TRS_MMC);
158
159 } else {
160
161 enable_record ();
162 }
163 }
164
165 void
mmc_record_exit(MIDI::MachineControl &)166 Session::mmc_record_exit (MIDI::MachineControl &/*mmc*/)
167 {
168 if (Config->get_mmc_control ()) {
169 disable_record (false);
170 }
171 }
172
173 void
mmc_stop(MIDI::MachineControl &)174 Session::mmc_stop (MIDI::MachineControl &/*mmc*/)
175 {
176 if (Config->get_mmc_control ()) {
177 request_stop ();
178 }
179 }
180
181 void
mmc_pause(MIDI::MachineControl &)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
mmc_step(MIDI::MachineControl &,int steps)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_fsm->transport_speed() == 0 || cur_speed * _transport_fsm->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_fsm->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
mmc_rewind(MIDI::MachineControl &)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
mmc_fast_forward(MIDI::MachineControl &)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
mmc_locate(MIDI::MachineControl &,const MIDI::byte * mmc_tc)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, MustStop);
310 }
311 }
312
313 void
mmc_shuttle(MIDI::MachineControl &,float speed,bool forw)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>
get_midi_nth_route_by_id(PresentationInfo::order_t n) const332 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
mmc_record_enable(MIDI::MachineControl & mmc,size_t trk,bool enabled)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 void
mtc_tx_resync_latency(bool playback)380 Session::mtc_tx_resync_latency (bool playback)
381 {
382 if (deletion_in_progress() || !playback) {
383 return;
384 }
385 boost::shared_ptr<Port> mtxport = _midi_ports->mtc_output_port ();
386 if (mtxport) {
387 mtxport->get_connected_latency_range(mtc_out_latency, true);
388 DEBUG_TRACE (DEBUG::MTC, string_compose ("resync latency: %1\n", mtc_out_latency.max));
389 }
390 }
391
392 /** Send MTC Full Frame message (complete Timecode time) for the start of this cycle.
393 * This resets the MTC code, the next quarter frame message that is sent will be
394 * the first one with the beginning of this cycle as the new start point.
395 * @param t time to send.
396 */
397 int
send_full_time_code(samplepos_t const t,MIDI::pframes_t nframes)398 Session::send_full_time_code (samplepos_t const t, MIDI::pframes_t nframes)
399 {
400 /* This function could easily send at a given sample offset, but would
401 * that be useful? Does ardour do sub-block accurate locating? [DR] */
402
403 MIDI::byte msg[10];
404 Timecode::Time timecode;
405
406 _send_timecode_update = false;
407
408 if (_engine.freewheeling() || !Config->get_send_mtc()) {
409 return 0;
410 }
411
412 if (transport_master_is_external() && !transport_master()->locked()) {
413 return 0;
414 }
415
416 // Get timecode time for the given time
417 sample_to_timecode (t, timecode, true /* use_offset */, false /* no subframes */);
418
419 // sample-align outbound to rounded (no subframes) timecode
420 samplepos_t mtc_tc;
421 timecode_to_sample(timecode, mtc_tc, true, false);
422 outbound_mtc_timecode_frame = mtc_tc;
423 transmitting_timecode_time = timecode;
424
425 sampleoffset_t mtc_offset = mtc_out_latency.max;
426
427 // only if rolling.. ?
428 outbound_mtc_timecode_frame += mtc_offset;
429
430 // outbound_mtc_timecode_frame needs to be >= _transport_sample
431 // or a new full timecode will be queued next cycle.
432 while (outbound_mtc_timecode_frame < t) {
433 Timecode::increment (transmitting_timecode_time, config.get_subframes_per_frame());
434 outbound_mtc_timecode_frame += _samples_per_timecode_frame;
435 }
436
437 double const quarter_frame_duration = ((samplecnt_t) _samples_per_timecode_frame) / 4.0;
438 if (ceil((t - mtc_tc) / quarter_frame_duration) > 0) {
439 Timecode::increment (transmitting_timecode_time, config.get_subframes_per_frame());
440 outbound_mtc_timecode_frame += _samples_per_timecode_frame;
441 }
442
443 DEBUG_TRACE (DEBUG::MTC, string_compose ("Full MTC TC %1 (off %2)\n", outbound_mtc_timecode_frame, mtc_offset));
444
445 /* according to MTC spec 24, 30 drop and 30 non-drop TC, the frame-number represented by 8 quarter frames must be even. */
446 if (((mtc_timecode_bits >> 5) != MIDI::MTC_25_FPS) && (transmitting_timecode_time.frames % 2)) {
447 /* start MTC quarter frame transmission on an even frame */
448 Timecode::increment (transmitting_timecode_time, config.get_subframes_per_frame());
449 outbound_mtc_timecode_frame += _samples_per_timecode_frame;
450 }
451
452 next_quarter_frame_to_send = 0;
453
454 // Sync slave to the same Timecode time as we are on
455 msg[0] = 0xf0;
456 msg[1] = 0x7f;
457 msg[2] = 0x7f;
458 msg[3] = 0x1;
459 msg[4] = 0x1;
460 msg[9] = 0xf7;
461
462 msg[5] = mtc_timecode_bits | (timecode.hours % 24);
463 msg[6] = timecode.minutes;
464 msg[7] = timecode.seconds;
465 msg[8] = timecode.frames;
466
467 // Send message at offset 0, sent time is for the start of this cycle
468
469 MidiBuffer& mb (_midi_ports->mtc_output_port()->get_midi_buffer (nframes));
470 mb.push_back (0, Evoral::MIDI_EVENT, sizeof (msg), msg);
471
472 _pframes_since_last_mtc = 0;
473 return 0;
474 }
475
476 /** Send MTC (quarter-frame) messages for this cycle.
477 * Must be called exactly once per cycle from the process thread. Realtime safe.
478 * This function assumes the state of full Timecode is sane, eg. the slave is
479 * expecting quarter frame messages and has the right frame of reference (any
480 * full MTC Timecode time messages that needed to be sent should have been sent
481 * earlier already this cycle by send_full_time_code)
482 */
483 int
send_midi_time_code_for_cycle(samplepos_t start_sample,samplepos_t end_sample,ARDOUR::pframes_t nframes)484 Session::send_midi_time_code_for_cycle (samplepos_t start_sample, samplepos_t end_sample, ARDOUR::pframes_t nframes)
485 {
486 // start_sample == start_sample for normal cycles
487 // start_sample > _transport_sample for split cycles
488 if (_engine.freewheeling() || !_send_qf_mtc || transmitting_timecode_time.negative || (next_quarter_frame_to_send < 0)) {
489 // cerr << "(MTC) Not sending MTC\n";
490 return 0;
491 }
492 if (transport_master_is_external() && !transport_master()->locked()) {
493 return 0;
494 }
495
496 if (_transport_fsm->transport_speed() < 0) {
497 // we don't support rolling backwards
498 return 0;
499 }
500
501 /* MTC is max. 30 fps - assert() below will fail
502 * TODO actually limit it to 24,25,29df,30fps
503 * talk to oofus, first.
504 */
505 if (Timecode::timecode_to_frames_per_second(config.get_timecode_format()) > 30) {
506 return 0;
507 }
508
509 assert (next_quarter_frame_to_send >= 0);
510 assert (next_quarter_frame_to_send <= 7);
511
512 /* Duration of one quarter frame */
513 double const quarter_frame_duration = _samples_per_timecode_frame / 4.0;
514
515 DEBUG_TRACE (DEBUG::MTC, string_compose ("TF %1 SF %2 MT %3 QF %4 QD %5\n",
516 _transport_sample, start_sample, outbound_mtc_timecode_frame,
517 next_quarter_frame_to_send, quarter_frame_duration));
518
519 if (rint(outbound_mtc_timecode_frame + (next_quarter_frame_to_send * quarter_frame_duration)) < _transport_sample) {
520 // send full timecode and set outbound_mtc_timecode_frame, next_quarter_frame_to_send
521 send_full_time_code (_transport_sample, nframes);
522 }
523
524 if (rint(outbound_mtc_timecode_frame + (next_quarter_frame_to_send * quarter_frame_duration)) < start_sample) {
525 // no QF for this cycle
526 return 0;
527 }
528
529 /* Send quarter frames for this cycle */
530 while (end_sample > rint(outbound_mtc_timecode_frame + (next_quarter_frame_to_send * quarter_frame_duration))) {
531
532 DEBUG_TRACE (DEBUG::MTC, string_compose ("next sample to send: %1\n", next_quarter_frame_to_send));
533
534 switch (next_quarter_frame_to_send) {
535 case 0:
536 mtc_msg[1] = 0x00 | (transmitting_timecode_time.frames & 0xf);
537 break;
538 case 1:
539 mtc_msg[1] = 0x10 | ((transmitting_timecode_time.frames & 0xf0) >> 4);
540 break;
541 case 2:
542 mtc_msg[1] = 0x20 | (transmitting_timecode_time.seconds & 0xf);
543 break;
544 case 3:
545 mtc_msg[1] = 0x30 | ((transmitting_timecode_time.seconds & 0xf0) >> 4);
546 break;
547 case 4:
548 mtc_msg[1] = 0x40 | (transmitting_timecode_time.minutes & 0xf);
549 break;
550 case 5:
551 mtc_msg[1] = 0x50 | ((transmitting_timecode_time.minutes & 0xf0) >> 4);
552 break;
553 case 6:
554 mtc_msg[1] = 0x60 | ((mtc_timecode_bits | transmitting_timecode_time.hours) & 0xf);
555 break;
556 case 7:
557 mtc_msg[1] = 0x70 | (((mtc_timecode_bits | transmitting_timecode_time.hours) & 0xf0) >> 4);
558 break;
559 }
560
561 const samplepos_t msg_time = rint (outbound_mtc_timecode_frame + (quarter_frame_duration * next_quarter_frame_to_send));
562
563 // This message must fall within this block or something is broken
564 assert (msg_time >= start_sample);
565 assert (msg_time < end_sample);
566
567 /* convert from session samples back to JACK samples using the transport speed */
568 ARDOUR::pframes_t const out_stamp = (msg_time - start_sample) / _transport_fsm->transport_speed();
569 assert (out_stamp < nframes);
570
571 MidiBuffer& mb (_midi_ports->mtc_output_port()->get_midi_buffer(nframes));
572 if (!mb.push_back (out_stamp, Evoral::MIDI_EVENT, 2, mtc_msg)) {
573 error << string_compose(_("Session: cannot send quarter-frame MTC message (%1)"), strerror (errno))
574 << endmsg;
575 return -1;
576 }
577
578 #ifndef NDEBUG
579 if (DEBUG_ENABLED(DEBUG::MTC)) {
580 DEBUG_STR_DECL(foo);
581 DEBUG_STR_APPEND(foo,"sending ");
582 DEBUG_STR_APPEND(foo, transmitting_timecode_time);
583 DEBUG_TRACE (DEBUG::MTC, string_compose ("%1 qfm = %2, stamp = %3\n", DEBUG_STR(foo).str(), next_quarter_frame_to_send,
584 out_stamp));
585 }
586 #endif
587
588 // Increment quarter frame counter
589 next_quarter_frame_to_send++;
590
591 if (next_quarter_frame_to_send >= 8) {
592 // Wrap quarter frame counter
593 next_quarter_frame_to_send = 0;
594 // Increment timecode time twice
595 Timecode::increment (transmitting_timecode_time, config.get_subframes_per_frame());
596 Timecode::increment (transmitting_timecode_time, config.get_subframes_per_frame());
597 // Increment timing of first quarter frame
598 outbound_mtc_timecode_frame += 2.0 * _samples_per_timecode_frame;
599 }
600 }
601
602 return 0;
603 }
604
605 /***********************************************************************
606 OUTBOUND MMC STUFF
607 **********************************************************************/
608
609 void
send_immediate_mmc(MachineControlCommand c)610 Session::send_immediate_mmc (MachineControlCommand c)
611 {
612 _mmc->send (c, 0);
613 }
614
615 bool
mmc_step_timeout()616 Session::mmc_step_timeout ()
617 {
618 struct timeval now;
619 struct timeval diff;
620 double diff_usecs;
621 gettimeofday (&now, 0);
622
623 timersub (&now, &last_mmc_step, &diff);
624 diff_usecs = diff.tv_sec * 1000000 + diff.tv_usec;
625
626 if (diff_usecs > 1000000.0 || fabs (_transport_fsm->transport_speed()) < 0.0000001) {
627 /* too long or too slow, stop transport */
628 request_stop ();
629 step_queued = false;
630 return false;
631 }
632
633 if (diff_usecs < 250000.0) {
634 /* too short, just keep going */
635 return true;
636 }
637
638 /* slow it down */
639
640 request_transport_speed_nonzero (actual_speed() * 0.75);
641 return true;
642 }
643
644 /* *********************************************************************
645 * OUTBOUND SYSTEM COMMON STUFF
646 **********************************************************************/
647
648 void
send_song_position_pointer(samplepos_t)649 Session::send_song_position_pointer (samplepos_t)
650 {
651 if (midi_clock) {
652 /* Do nothing for the moment */
653 }
654 }
655
656 int
start_midi_thread()657 Session::start_midi_thread ()
658 {
659 if (midi_control_ui) { return 0; }
660 midi_control_ui = new MidiControlUI (*this);
661 midi_control_ui->run ();
662 return 0;
663 }
664
665 boost::shared_ptr<ARDOUR::Port>
mmc_output_port() const666 Session::mmc_output_port () const
667 {
668 return _midi_ports->mmc_output_port ();
669 }
670
671 boost::shared_ptr<ARDOUR::Port>
mmc_input_port() const672 Session::mmc_input_port () const
673 {
674 return _midi_ports->mmc_input_port ();
675 }
676
677 boost::shared_ptr<ARDOUR::Port>
scene_output_port() const678 Session::scene_output_port () const
679 {
680 return _midi_ports->scene_output_port ();
681 }
682
683 boost::shared_ptr<ARDOUR::Port>
scene_input_port() const684 Session::scene_input_port () const
685 {
686 return _midi_ports->scene_input_port ();
687 }
688
689 boost::shared_ptr<AsyncMIDIPort>
vkbd_output_port() const690 Session::vkbd_output_port () const
691 {
692 return _midi_ports->vkbd_output_port ();
693 }
694
695 boost::shared_ptr<MidiPort>
midi_clock_output_port() const696 Session::midi_clock_output_port () const
697 {
698 return _midi_ports->midi_clock_output_port ();
699 }
700
701 boost::shared_ptr<MidiPort>
mtc_output_port() const702 Session::mtc_output_port () const
703 {
704 return _midi_ports->mtc_output_port ();
705 }
706
707 void
midi_track_presentation_info_changed(PropertyChange const & what_changed,boost::weak_ptr<MidiTrack> mt)708 Session::midi_track_presentation_info_changed (PropertyChange const& what_changed, boost::weak_ptr<MidiTrack> mt)
709 {
710 if (!Config->get_midi_input_follows_selection()) {
711 return;
712 }
713
714 if (!what_changed.contains (Properties::selected)) {
715 return;
716 }
717
718 boost::shared_ptr<MidiTrack> new_midi_target (mt.lock ());
719
720 if (new_midi_target->is_selected()) {
721 rewire_selected_midi (new_midi_target);
722 }
723 }
724
725 void
rewire_selected_midi(boost::shared_ptr<MidiTrack> new_midi_target)726 Session::rewire_selected_midi (boost::shared_ptr<MidiTrack> new_midi_target)
727 {
728 if (!new_midi_target) {
729 return;
730 }
731
732 boost::shared_ptr<MidiTrack> old_midi_target = current_midi_target.lock ();
733
734 if (new_midi_target == old_midi_target) {
735 return;
736 }
737
738 vector<string> msp;
739 AudioEngine::instance()->get_midi_selection_ports (msp);
740
741 if (!msp.empty()) {
742
743 for (vector<string>::const_iterator p = msp.begin(); p != msp.end(); ++p) {
744 MidiPortFlags mpf = AudioEngine::instance()->midi_port_metadata (*p);
745
746 /* if a port is marked for control data, do not
747 * disconnect it from everything since it may also be
748 * used via a control surface or some other
749 * functionality.
750 */
751
752 if (0 == (mpf & MidiPortControl)) {
753 /* disconnect the port from everything */
754 AudioEngine::instance()->disconnect (*p);
755 } else {
756 /* only disconnect from non-control ports */
757 vector<string> port_connections;
758 AudioEngine::instance()->get_connections (*p, port_connections);
759 for (vector<string>::iterator i = port_connections.begin(); i != port_connections.end(); ++i) {
760 /* test if (*i) is a control-surface input port */
761 if (AudioEngine::instance()->port_is_control_only (*i)) {
762 continue;
763 }
764 AudioEngine::instance()->disconnect (*p, *i);
765 }
766 }
767 /* connect it to the new target */
768 new_midi_target->input()->connect (new_midi_target->input()->nth(0), (*p), this);
769 }
770 }
771
772 current_midi_target = new_midi_target;
773 }
774
775 void
rewire_midi_selection_ports()776 Session::rewire_midi_selection_ports ()
777 {
778 if (!Config->get_midi_input_follows_selection()) {
779 return;
780 }
781
782 boost::shared_ptr<MidiTrack> target = current_midi_target.lock();
783
784 if (!target) {
785 return;
786 }
787
788 vector<string> msp;
789 AudioEngine::instance()->get_midi_selection_ports (msp);
790
791 if (msp.empty()) {
792 return;
793 }
794
795 target->input()->disconnect (this);
796
797 for (vector<string>::const_iterator p = msp.begin(); p != msp.end(); ++p) {
798 AudioEngine::instance()->disconnect (*p);
799 target->input()->connect (target->input()->nth (0), (*p), this);
800 }
801 }
802