X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsession_midi.cc;h=fa23880b87bef6504618295f4529d8b72a738ceb;hb=cf52d6e4b40111eb04b244ec054055a4ec15dbe0;hp=ea6dfe81cf17f6bd5f9bb5542103af04f39a90b5;hpb=d135c4dc3a307d0be606f3afbbc8fd8c3ec56438;p=ardour.git diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc index ea6dfe81cf..fa23880b87 100644 --- a/libs/ardour/session_midi.cc +++ b/libs/ardour/session_midi.cc @@ -33,6 +33,7 @@ #include "pbd/error.h" #include "pbd/pthread_utils.h" #include "pbd/timersub.h" +#include "pbd/stacktrace.h" #include "timecode/time.h" @@ -42,11 +43,12 @@ #include "ardour/midi_port.h" #include "ardour/midi_track.h" #include "ardour/midi_ui.h" +#include "ardour/profile.h" #include "ardour/session.h" #include "ardour/slave.h" #include "ardour/ticker.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace std; using namespace ARDOUR; @@ -128,6 +130,19 @@ Session::mmc_record_pause (MIDI::MachineControl &/*mmc*/) void Session::mmc_record_strobe (MIDI::MachineControl &/*mmc*/) { + if (Profile->get_trx()) { + + /* In Tracks Live, there is no concept of punch, so we just + treat RecordStrobe like RecordPause. This violates the MMC + specification. + */ + + if (Config->get_mmc_control()) { + maybe_enable_record(); + } + return; + } + if (!Config->get_mmc_control() || (_step_editors > 0)) { return; } @@ -320,6 +335,36 @@ Session::mmc_shuttle (MIDI::MachineControl &/*mmc*/, float speed, bool forw) } } +boost::shared_ptr +Session::get_midi_nth_route_by_id (PresentationInfo::order_t n) const +{ + PresentationInfo::Flag f; + + /* These numbers are defined by the MMC specification. + */ + + if (n == 318) { + f = PresentationInfo::MasterOut; + } else if (n == 319) { + f = PresentationInfo::MonitorOut; + } else { + f = PresentationInfo::Route; + } + + boost::shared_ptr r = routes.reader (); + PresentationInfo::order_t match_cnt = 0; + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + if ((*i)->presentation_info().flag_match (f)) { + if (match_cnt++ == n) { + return *i; + } + } + } + + return boost::shared_ptr(); +} + void Session::mmc_record_enable (MIDI::MachineControl &mmc, size_t trk, bool enabled) { @@ -327,17 +372,13 @@ Session::mmc_record_enable (MIDI::MachineControl &mmc, size_t trk, bool enabled) return; } - RouteList::iterator i; - boost::shared_ptr r = routes.reader(); + boost::shared_ptr r = get_midi_nth_route_by_id (trk); - for (i = r->begin(); i != r->end(); ++i) { - AudioTrack *at; + if (r) { + boost::shared_ptr at; - if ((at = dynamic_cast((*i).get())) != 0) { - if (trk == at->remote_control_id()) { - at->set_record_enabled (enabled, &mmc); - break; - } + if ((at = boost::dynamic_pointer_cast (r))) { + at->rec_enable_control()->set_value (enabled, Controllable::UseGroup); } } } @@ -372,16 +413,29 @@ Session::send_full_time_code (framepos_t const t, MIDI::pframes_t nframes) framepos_t mtc_tc; timecode_to_sample(timecode, mtc_tc, true, false); outbound_mtc_timecode_frame = mtc_tc; - transmitting_timecode_time = timecode; + LatencyRange mtc_out_latency = {0, 0}; // TODO cache this, update on engine().GraphReordered() + _midi_ports->mtc_output_port ()->get_connected_latency_range (ltc_out_latency, true); + frameoffset_t mtc_offset = worst_playback_latency() - mtc_out_latency.max; + + // only if rolling.. ? + outbound_mtc_timecode_frame += mtc_offset; + + // outbound_mtc_timecode_frame needs to be >= _transport_frame + // or a new full timecode will be queued next cycle. + while (outbound_mtc_timecode_frame < t) { + Timecode::increment (transmitting_timecode_time, config.get_subframes_per_frame()); + outbound_mtc_timecode_frame += _frames_per_timecode_frame; + } + double const quarter_frame_duration = ((framecnt_t) _frames_per_timecode_frame) / 4.0; if (ceil((t - mtc_tc) / quarter_frame_duration) > 0) { Timecode::increment (transmitting_timecode_time, config.get_subframes_per_frame()); outbound_mtc_timecode_frame += _frames_per_timecode_frame; } - DEBUG_TRACE (DEBUG::MTC, string_compose ("Full MTC TC %1\n", outbound_mtc_timecode_frame)); + DEBUG_TRACE (DEBUG::MTC, string_compose ("Full MTC TC %1 (off %2)\n", outbound_mtc_timecode_frame, mtc_offset)); // I don't understand this bit yet.. [DR] // I do [rg]: @@ -392,21 +446,6 @@ Session::send_full_time_code (framepos_t const t, MIDI::pframes_t nframes) outbound_mtc_timecode_frame += _frames_per_timecode_frame; } -#if 0 // compensate for audio latency -- disabled [rg] - /* this needs more thought and work. - * the proper solution will be to just offset MTC by the MIDI port's latency. - * - * using worst_playback_latency() is wrong when the generated MTC is used to sync - * clients which send audio to Ardour for recording. - * worst_capture_latency() vs. worst_playback_latency() - * - * NB. similarly to session_ltc, the offset should be subtracted from the timecode to send, - * instead of being added to timestamp when to send the timecode. - * Otherwise the timestamp may not fall into the jack-cycle of the current _transport frame. - * and no MTC QF will be sent. - */ - outbound_mtc_timecode_frame += worst_playback_latency(); -#endif next_quarter_frame_to_send = 0; // Sync slave to the same Timecode time as we are on @@ -417,15 +456,15 @@ Session::send_full_time_code (framepos_t const t, MIDI::pframes_t nframes) msg[4] = 0x1; msg[9] = 0xf7; - msg[5] = mtc_timecode_bits | timecode.hours; + msg[5] = mtc_timecode_bits | (timecode.hours % 24); msg[6] = timecode.minutes; msg[7] = timecode.seconds; msg[8] = timecode.frames; // Send message at offset 0, sent time is for the start of this cycle - + MidiBuffer& mb (_midi_ports->mtc_output_port()->get_midi_buffer (nframes)); - mb.push_back (0, sizeof (msg), msg); + mb.push_back (Port::port_offset(), sizeof (msg), msg); _pframes_since_last_mtc = 0; return 0; @@ -441,6 +480,8 @@ Session::send_full_time_code (framepos_t const t, MIDI::pframes_t nframes) int Session::send_midi_time_code_for_cycle (framepos_t start_frame, framepos_t end_frame, ARDOUR::pframes_t nframes) { + // start_frame == start_frame for normal cycles + // start_frame > _transport_frame for split cycles if (_engine.freewheeling() || !_send_qf_mtc || transmitting_timecode_time.negative || (next_quarter_frame_to_send < 0)) { // cerr << "(MTC) Not sending MTC\n"; return 0; @@ -449,6 +490,11 @@ Session::send_midi_time_code_for_cycle (framepos_t start_frame, framepos_t end_f return 0; } + if (_transport_speed < 0) { + // we don't support rolling backwards + return 0; + } + /* MTC is max. 30 fps - assert() below will fail * TODO actually limit it to 24,25,29df,30fps * talk to oofus, first. @@ -468,7 +514,12 @@ Session::send_midi_time_code_for_cycle (framepos_t start_frame, framepos_t end_f next_quarter_frame_to_send, quarter_frame_duration)); if (rint(outbound_mtc_timecode_frame + (next_quarter_frame_to_send * quarter_frame_duration)) < _transport_frame) { + // send full timecode and set outbound_mtc_timecode_frame, next_quarter_frame_to_send send_full_time_code (_transport_frame, nframes); + } + + if (rint(outbound_mtc_timecode_frame + (next_quarter_frame_to_send * quarter_frame_duration)) < start_frame) { + // no QF for this cycle return 0; } @@ -522,11 +573,13 @@ Session::send_midi_time_code_for_cycle (framepos_t start_frame, framepos_t end_f } #ifndef NDEBUG - DEBUG_STR_DECL(foo) - DEBUG_STR_APPEND(foo,"sending "); - DEBUG_STR_APPEND(foo, transmitting_timecode_time); - DEBUG_TRACE (DEBUG::MTC, string_compose ("%1 qfm = %2, stamp = %3\n", DEBUG_STR(foo).str(), next_quarter_frame_to_send, - out_stamp)); + if (DEBUG_ENABLED(DEBUG::MTC)) { + DEBUG_STR_DECL(foo) + DEBUG_STR_APPEND(foo,"sending "); + DEBUG_STR_APPEND(foo, transmitting_timecode_time); + DEBUG_TRACE (DEBUG::MTC, string_compose ("%1 qfm = %2, stamp = %3\n", DEBUG_STR(foo).str(), next_quarter_frame_to_send, + out_stamp)); + } #endif // Increment quarter frame counter @@ -538,8 +591,7 @@ Session::send_midi_time_code_for_cycle (framepos_t start_frame, framepos_t end_f // Increment timecode time twice Timecode::increment (transmitting_timecode_time, config.get_subframes_per_frame()); Timecode::increment (transmitting_timecode_time, config.get_subframes_per_frame()); - // Re-calculate timing of first quarter frame - //timecode_to_sample( transmitting_timecode_time, outbound_mtc_timecode_frame, true /* use_offset */, false ); + // Increment timing of first quarter frame outbound_mtc_timecode_frame += 2.0 * _frames_per_timecode_frame; } } @@ -551,6 +603,16 @@ Session::send_midi_time_code_for_cycle (framepos_t start_frame, framepos_t end_f OUTBOUND MMC STUFF **********************************************************************/ +void +Session::send_immediate_mmc (MachineControlCommand c) +{ + if (AudioEngine::instance()->in_process_thread()) { + _mmc->send (c, Port::port_offset()); + } else { + _mmc->send (c, 0); + } + +} bool Session::mmc_step_timeout () @@ -597,50 +659,66 @@ Session::send_song_position_pointer (framepos_t) int Session::start_midi_thread () { + if (midi_control_ui) { return 0; } midi_control_ui = new MidiControlUI (*this); midi_control_ui->run (); return 0; } -MIDI::Port* +boost::shared_ptr Session::midi_input_port () const { return _midi_ports->midi_input_port (); } -MIDI::Port* + +boost::shared_ptr Session::midi_output_port () const { return _midi_ports->midi_output_port (); } -boost::shared_ptr + +boost::shared_ptr +Session::mmc_output_port () const +{ + return _midi_ports->mmc_output_port (); +} + +boost::shared_ptr +Session::mmc_input_port () const +{ + return _midi_ports->mmc_input_port (); +} + +boost::shared_ptr +Session::scene_output_port () const +{ + return _midi_ports->scene_output_port (); +} + +boost::shared_ptr +Session::scene_input_port () const +{ + return _midi_ports->scene_input_port (); +} + +boost::shared_ptr Session::midi_clock_output_port () const { return _midi_ports->midi_clock_output_port (); } -boost::shared_ptr + +boost::shared_ptr Session::midi_clock_input_port () const { return _midi_ports->midi_clock_input_port (); } -boost::shared_ptr +boost::shared_ptr Session::mtc_output_port () const { return _midi_ports->mtc_output_port (); } -boost::shared_ptr +boost::shared_ptr Session::mtc_input_port () const { return _midi_ports->mtc_input_port (); } - -MIDI::Port* -Session::mmc_output_port () const -{ - return _midi_ports->mmc_output_port (); -} - -MIDI::Port* -Session::mmc_input_port () const -{ - return _midi_ports->mmc_input_port (); -}