X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fsession_midi.cc;h=b4938636a2b97ffd1d67e7048c6b9e9280695305;hb=44fd104ada0fbd8b76d34150e941d85d6de6f81b;hp=56e593086a07c5405318fe682dfcbdd1fda7daaa;hpb=a20f41ab39cc034740ccd564c1057d8737d763d5;p=ardour.git diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc index 56e593086a..b4938636a2 100644 --- a/libs/ardour/session_midi.cc +++ b/libs/ardour/session_midi.cc @@ -16,42 +16,60 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ */ #include #include #include +#include #include #include #include +#include + #include #include #include #include -#include +#include #include #include #include #include #include -#include +#include +#include #include #include +#include #include "i18n.h" using namespace std; using namespace ARDOUR; -//using namespace sigc; +using namespace PBD; using namespace MIDI; MachineControl::CommandSignature MMC_CommandSignature; MachineControl::ResponseSignature MMC_ResponseSignature; -MultiAllocSingleReleasePool Session::MIDIRequest::pool ("midi", sizeof (Session::MIDIRequest), 1024); + +void +Session::midi_panic() +{ + { + boost::shared_ptr r = routes.reader (); + + for (RouteList::iterator i = r->begin(); i != r->end(); ++i) { + MidiTrack *track = dynamic_cast((*i).get()); + if (track != 0) { + track->midi_panic(); + } + } + } +} int Session::use_config_midi_ports () @@ -84,100 +102,6 @@ Session::use_config_midi_ports () MTC, MMC, etc. **********************************************************************/ -void -Session::set_mmc_control (bool yn) -{ - if (mmc_control == yn) { - return; - } - - mmc_control = yn; - set_dirty(); - poke_midi_thread (); - - ControlChanged (MMCControl); /* EMIT SIGNAL */ -} - -void -Session::set_midi_control (bool yn) -{ - if (midi_control == yn) { - return; - } - - midi_control = yn; - set_dirty(); - poke_midi_thread (); - - if (_midi_port) { - RWLockMonitor lm (route_lock, false, __LINE__, __FILE__); - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { - (*i)->reset_midi_control (_midi_port, midi_control); - } - } - - ControlChanged (MidiControl); /* EMIT SIGNAL */ -} - -void -Session::set_send_mtc (bool yn) -{ - /* set the persistent option value regardless */ - - send_midi_timecode = yn; - set_dirty(); - - /* only set the internal flag if we have - a port. - */ - - if (_mtc_port == 0 || send_mtc == yn) { - return; - } - - send_mtc = yn; - ControlChanged (SendMTC); /* EMIT SIGNAL */ -} - -void -Session::set_send_mmc (bool yn) -{ - if (_mmc_port == 0) { - return; - } - - if (send_midi_machine_control == yn) { - return; - } - - /* only set the internal flag if we have - a port. - */ - - if (_mmc_port) { - send_mmc = yn; - } - - /* set the persistent option value regardless */ - - send_midi_machine_control = yn; - set_dirty(); - - ControlChanged (SendMMC); /* EMIT SIGNAL */ -} - -bool -Session::get_send_mtc () const -{ - return send_mtc; -} - -bool -Session::get_send_mmc () const -{ - return send_mmc; -} - int Session::set_mtc_port (string port_tag) { @@ -220,9 +144,29 @@ Session::set_mtc_port (string port_tag) return 0; } +void +Session::set_mmc_receive_device_id (uint32_t device_id) +{ + if (mmc) { + mmc->set_receive_device_id (device_id); + } +} + +void +Session::set_mmc_send_device_id (uint32_t device_id) +{ + if (mmc) { + mmc->set_send_device_id (device_id); + } +} + int Session::set_mmc_port (string port_tag) { + MIDI::byte old_recv_device_id = 0; + MIDI::byte old_send_device_id = 0; + bool reset_id = false; + if (port_tag.length() == 0) { if (_mmc_port == 0) { return 0; @@ -240,6 +184,9 @@ Session::set_mmc_port (string port_tag) _mmc_port = port; if (mmc) { + old_recv_device_id = mmc->receive_device_id(); + old_recv_device_id = mmc->send_device_id(); + reset_id = true; delete mmc; } @@ -247,6 +194,10 @@ Session::set_mmc_port (string port_tag) MMC_CommandSignature, MMC_ResponseSignature); + if (reset_id) { + mmc->set_receive_device_id (old_recv_device_id); + mmc->set_send_device_id (old_send_device_id); + } mmc->Play.connect (mem_fun (*this, &Session::mmc_deferred_play)); @@ -275,6 +226,7 @@ Session::set_mmc_port (string port_tag) mmc->TrackRecordStatusChange.connect (mem_fun (*this, &Session::mmc_record_enable)); + /* also handle MIDI SPP because its so common */ _mmc_port->input()->start.connect (mem_fun (*this, &Session::spp_start)); @@ -293,6 +245,7 @@ Session::set_mmc_port (string port_tag) int Session::set_midi_port (string port_tag) { +#if 0 if (port_tag.length() == 0) { if (_midi_port == 0) { return 0; @@ -308,10 +261,15 @@ Session::set_midi_port (string port_tag) } _midi_port = port; + + /* XXX need something to forward this to control protocols ? or just + use the signal below + */ Config->set_midi_port_name (port_tag); out: +#endif MIDI_PortChanged(); /* EMIT SIGNAL */ change_midi_ports (); set_dirty(); @@ -449,53 +407,17 @@ Session::get_trace_midi_output(MIDI::Port *port) } - -void -Session::set_midi_feedback (bool yn) -{ - if (_midi_port == 0) { - return; - } - - midi_feedback = yn; - set_dirty(); - - if (yn) { - /* make sure the feedback thread is alive */ - start_feedback (); - } else { - /* maybe put the feedback thread to sleep */ - stop_feedback (); - } - - ControlChanged (MidiFeedback); /* EMIT SIGNAL */ - - send_all_midi_feedback (); -} - -void -Session::send_all_midi_feedback () -{ - if (midi_feedback) { - // send out current state of all routes - RWLockMonitor lm (route_lock, false, __LINE__, __FILE__); - for (RouteList::iterator i = routes.begin(); i != routes.end(); ++i) { - (*i)->send_all_midi_feedback (); - } - } -} - void Session::setup_midi_control () { outbound_mtc_smpte_frame = 0; - next_quarter_frame_to_send = -1; + next_quarter_frame_to_send = 0; /* setup the MMC buffer */ mmc_buffer[0] = 0xf0; // SysEx mmc_buffer[1] = 0x7f; // Real Time SysEx ID for MMC - mmc_buffer[2] = 0x7f; // "broadcast" device ID + mmc_buffer[2] = (mmc ? mmc->send_device_id() : 0x7f); mmc_buffer[3] = 0x6; // MCC /* Set up the qtr frame message */ @@ -508,69 +430,12 @@ Session::setup_midi_control () mtc_msg[10] = 0xf1; mtc_msg[12] = 0xf1; mtc_msg[14] = 0xf1; - - if (_mmc_port != 0) { - - send_mmc = send_midi_machine_control; - - } else { - - mmc = 0; - send_mmc = false; - } - - if (_mtc_port != 0) { - - send_mtc = send_midi_timecode; - - } else { - - send_mtc = false; - } -} - -int -Session::midi_read (MIDI::Port* port) -{ - MIDI::byte buf[512]; - - /* reading from the MIDI port activates the Parser - that in turn generates signals that we care - about. the port is already set to NONBLOCK so that - can read freely here. - */ - - while (1) { - - // cerr << "+++ READ ON " << port->name() << endl; - - int nread = port->read (buf, sizeof (buf)); - - // cerr << "-- READ (" << nread << " ON " << port->name() << endl; - - if (nread > 0) { - if ((size_t) nread < sizeof (buf)) { - break; - } else { - continue; - } - } else if (nread == 0) { - break; - } else if (errno == EAGAIN) { - break; - } else { - fatal << string_compose(_("Error reading from MIDI port %1"), port->name()) << endmsg; - /*NOTREACHED*/ - } - } - - return 0; } void Session::spp_start (Parser& ignored) { - if (mmc_control && (_slave_type != MTC)) { + if (Config->get_mmc_control() && (Config->get_slave_source() != MTC)) { request_transport_speed (1.0); } } @@ -584,7 +449,7 @@ Session::spp_continue (Parser& ignored) void Session::spp_stop (Parser& ignored) { - if (mmc_control) { + if (Config->get_mmc_control()) { request_stop (); } } @@ -592,7 +457,7 @@ Session::spp_stop (Parser& ignored) void Session::mmc_deferred_play (MIDI::MachineControl &mmc) { - if (mmc_control && (_slave_type != MTC)) { + if (Config->get_mmc_control() && (Config->get_slave_source() != MTC)) { request_transport_speed (1.0); } } @@ -600,7 +465,7 @@ Session::mmc_deferred_play (MIDI::MachineControl &mmc) void Session::mmc_record_pause (MIDI::MachineControl &mmc) { - if (mmc_control) { + if (Config->get_mmc_control()) { maybe_enable_record(); } } @@ -608,7 +473,7 @@ Session::mmc_record_pause (MIDI::MachineControl &mmc) void Session::mmc_record_strobe (MIDI::MachineControl &mmc) { - if (!mmc_control) + if (!Config->get_mmc_control()) return; /* record strobe does an implicit "Play" command */ @@ -622,8 +487,8 @@ Session::mmc_record_strobe (MIDI::MachineControl &mmc) */ save_state ("", true); - atomic_set (&_record_status, Enabled); - RecordEnabled (); /* EMIT SIGNAL */ + g_atomic_int_set (&_record_status, Enabled); + RecordStateChanged (); /* EMIT SIGNAL */ request_transport_speed (1.0); @@ -636,15 +501,15 @@ Session::mmc_record_strobe (MIDI::MachineControl &mmc) void Session::mmc_record_exit (MIDI::MachineControl &mmc) { - if (mmc_control) { - disable_record (); + if (Config->get_mmc_control()) { + disable_record (false); } } void Session::mmc_stop (MIDI::MachineControl &mmc) { - if (mmc_control) { + if (Config->get_mmc_control()) { request_stop (); } } @@ -652,7 +517,7 @@ Session::mmc_stop (MIDI::MachineControl &mmc) void Session::mmc_pause (MIDI::MachineControl &mmc) { - if (mmc_control) { + if (Config->get_mmc_control()) { /* We support RECORD_PAUSE, so the spec says that we must interpret PAUSE like RECORD_PAUSE if @@ -670,10 +535,9 @@ Session::mmc_pause (MIDI::MachineControl &mmc) static bool step_queued = false; void - Session::mmc_step (MIDI::MachineControl &mmc, int steps) { - if (!mmc_control) { + if (!Config->get_mmc_control()) { return; } @@ -692,7 +556,7 @@ Session::mmc_step (MIDI::MachineControl &mmc, int steps) } double diff_secs = diff.tv_sec + (diff.tv_usec / 1000000.0); - double cur_speed = (((steps * 0.5) * smpte_frames_per_second) / diff_secs) / smpte_frames_per_second; + double cur_speed = (((steps * 0.5) * smpte_frames_per_second()) / diff_secs) / smpte_frames_per_second(); if (_transport_speed == 0 || cur_speed * _transport_speed < 0) { /* change direction */ @@ -724,7 +588,7 @@ Session::mmc_step (MIDI::MachineControl &mmc, int steps) void Session::mmc_rewind (MIDI::MachineControl &mmc) { - if (mmc_control) { + if (Config->get_mmc_control()) { request_transport_speed(-8.0f); } } @@ -732,7 +596,7 @@ Session::mmc_rewind (MIDI::MachineControl &mmc) void Session::mmc_fast_forward (MIDI::MachineControl &mmc) { - if (mmc_control) { + if (Config->get_mmc_control()) { request_transport_speed(8.0f); } } @@ -740,17 +604,19 @@ Session::mmc_fast_forward (MIDI::MachineControl &mmc) void Session::mmc_locate (MIDI::MachineControl &mmc, const MIDI::byte* mmc_tc) { - if (!mmc_control) { + if (!Config->get_mmc_control()) { return; } - jack_nframes_t target_frame; - SMPTE_Time smpte; + nframes_t target_frame; + SMPTE::Time smpte; smpte.hours = mmc_tc[0] & 0xf; smpte.minutes = mmc_tc[1]; smpte.seconds = mmc_tc[2]; smpte.frames = mmc_tc[3]; + smpte.rate = smpte_frames_per_second(); + smpte.drop = smpte_drop_frames(); // Also takes smpte offset into account: smpte_to_sample( smpte, target_frame, true /* use_offset */, false /* use_subframes */ ); @@ -779,18 +645,14 @@ Session::mmc_locate (MIDI::MachineControl &mmc, const MIDI::byte* mmc_tc) void Session::mmc_shuttle (MIDI::MachineControl &mmc, float speed, bool forw) { - cerr << "MMC shuttle, speed = " << speed << endl; - - if (!mmc_control) { + if (!Config->get_mmc_control()) { return; } - if (shuttle_speed_threshold >= 0 && speed > shuttle_speed_threshold) { - speed *= shuttle_speed_factor; + if (Config->get_shuttle_speed_threshold() >= 0 && speed > Config->get_shuttle_speed_threshold()) { + speed *= Config->get_shuttle_speed_factor(); } - cerr << "requested MMC control speed = " << speed << endl; - if (forw) { request_transport_speed (speed); } else { @@ -801,15 +663,15 @@ Session::mmc_shuttle (MIDI::MachineControl &mmc, float speed, bool forw) void Session::mmc_record_enable (MIDI::MachineControl &mmc, size_t trk, bool enabled) { - if (mmc_control) { + if (Config->get_mmc_control()) { RouteList::iterator i; - RWLockMonitor (route_lock, false, __LINE__, __FILE__); + boost::shared_ptr r = routes.reader(); - for (i = routes.begin(); i != routes.end(); ++i) { + for (i = r->begin(); i != r->end(); ++i) { AudioTrack *at; - if ((at = dynamic_cast(*i)) != 0) { + if ((at = dynamic_cast((*i).get())) != 0) { if (trk == at->remote_control_id()) { at->set_record_enable (enabled, &mmc); break; @@ -819,51 +681,6 @@ Session::mmc_record_enable (MIDI::MachineControl &mmc, size_t trk, bool enabled) } } -void -Session::send_full_time_code_in_another_thread () -{ - send_time_code_in_another_thread (true); -} - -void -Session::send_midi_time_code_in_another_thread () -{ - send_time_code_in_another_thread (false); -} - -void -Session::send_time_code_in_another_thread (bool full) -{ - jack_nframes_t two_smpte_frames_duration; - jack_nframes_t quarter_frame_duration; - - /* Duration of two smpte frames */ - two_smpte_frames_duration = ((long) _frames_per_smpte_frame) << 1; - - /* Duration of one quarter frame */ - quarter_frame_duration = ((long) _frames_per_smpte_frame) >> 2; - - if (_transport_frame < (outbound_mtc_smpte_frame + (next_quarter_frame_to_send * quarter_frame_duration))) - { - /* There is no work to do. - We throttle this here so that we don't overload - the transport thread with requests. - */ - return; - } - - MIDIRequest* request = new MIDIRequest; - - if (full) { - request->type = MIDIRequest::SendFullMTC; - } else { - request->type = MIDIRequest::SendMTC; - } - - midi_requests.write (&request, 1); - poke_midi_thread (); -} - void Session::change_midi_ports () { @@ -874,45 +691,45 @@ Session::change_midi_ports () poke_midi_thread (); } -int -Session::send_full_time_code () +/** Send MTC Full Frame message (complete SMPTE time) for the start of this cycle. + * This resets the MTC code, the next quarter frame message that is sent will be + * the first one with the beginning of this cycle as the new start point. + */ +int +Session::send_full_time_code(nframes_t nframes) { + /* This function could easily send at a given frame offset, but would + * that be useful? Does ardour do sub-block accurate locating? [DR] */ + MIDI::byte msg[10]; - SMPTE_Time smpte; + SMPTE::Time smpte; + + _send_smpte_update = false; - if (_mtc_port == 0 || !send_mtc) { + if (_mtc_port == 0 || !session_send_mtc) { return 0; } - + // Get smpte time for this transport frame sample_to_smpte(_transport_frame, smpte, true /* use_offset */, false /* no subframes */); - // Check for negative smpte time and prepare for quarter frame transmission - if (smpte.negative) { - // Negative mtc is not defined, so sync slave to smpte zero. - // When _transport_frame gets there we will start transmitting quarter frames - smpte.hours = 0; - smpte.minutes = 0; - smpte.seconds = 0; - smpte.frames = 0; - smpte.subframes = 0; - smpte.negative = false; - smpte_to_sample( smpte, outbound_mtc_smpte_frame, true, false ); - transmitting_smpte_time = smpte; - } else { - transmitting_smpte_time = smpte; - outbound_mtc_smpte_frame = _transport_frame; - if (((mtc_smpte_bits >> 5) != MIDI::MTC_25_FPS) && (transmitting_smpte_time.frames % 2)) { - // start MTC quarter frame transmission on an even frame - smpte_increment( transmitting_smpte_time ); - outbound_mtc_smpte_frame += (jack_nframes_t) _frames_per_smpte_frame; - } + transmitting_smpte_time = smpte; + outbound_mtc_smpte_frame = _transport_frame; + + // I don't understand this bit yet.. [DR] + if (((mtc_smpte_bits >> 5) != MIDI::MTC_25_FPS) && (transmitting_smpte_time.frames % 2)) { + // start MTC quarter frame transmission on an even frame + SMPTE::increment( transmitting_smpte_time ); + outbound_mtc_smpte_frame += (nframes_t) _frames_per_smpte_frame; } + // Compensate for audio latency + outbound_mtc_smpte_frame += _worst_output_latency; + next_quarter_frame_to_send = 0; - // Sync slave to the same smpte time as we are on (except if negative, see above) + // Sync slave to the same SMPTE time as we are on msg[0] = 0xf0; msg[1] = 0x7f; msg[2] = 0x7f; @@ -925,42 +742,55 @@ Session::send_full_time_code () msg[7] = smpte.seconds; msg[8] = smpte.frames; - { - LockMonitor lm (midi_lock, __LINE__, __FILE__); - - if (_mtc_port->midimsg (msg, sizeof (msg))) { - error << _("Session: could not send full MIDI time code") << endmsg; - - return -1; - } + cerr << "MTC: Sending full time code at " << outbound_mtc_smpte_frame << endl; + + // Send message at offset 0, sent time is for the start of this cycle + if (_mtc_port->midimsg (msg, sizeof (msg), 0)) { + error << _("Session: could not send full MIDI time code") << endmsg; + return -1; } return 0; } + +/** Sends MTC (quarter-frame) messages for this cycle. + * Must be called exactly once per cycle from the audio thread. Realtime safe. + * This function assumes the state of full SMPTE is sane, eg. the slave is + * expecting quarter frame messages and has the right frame of reference (any + * full MTC SMPTE time messages that needed to be sent should have been sent + * earlier already this cycle by send_full_time_code) + */ int -Session::send_midi_time_code () -{ - if (_mtc_port == 0 || !send_mtc || transmitting_smpte_time.negative || (next_quarter_frame_to_send < 0) ) { +Session::send_midi_time_code_for_cycle(nframes_t nframes) +{ + assert (next_quarter_frame_to_send >= 0); + assert (next_quarter_frame_to_send <= 7); + + if (_mtc_port == 0 || !session_send_mtc || transmitting_smpte_time.negative + /*|| (next_quarter_frame_to_send < 0)*/ ) { + // cerr << "(MTC) Not sending MTC\n"; return 0; } - - jack_nframes_t two_smpte_frames_duration; - jack_nframes_t quarter_frame_duration; - - /* Duration of two smpte frames */ - two_smpte_frames_duration = ((long) _frames_per_smpte_frame) << 1; - + /* Duration of one quarter frame */ - quarter_frame_duration = ((long) _frames_per_smpte_frame) >> 2; - - while (_transport_frame >= (outbound_mtc_smpte_frame + (next_quarter_frame_to_send * quarter_frame_duration))) { + nframes_t quarter_frame_duration = ((long) _frames_per_smpte_frame) >> 2; + + // cerr << "(MTC) TR: " << _transport_frame << " - SF: " << outbound_mtc_smpte_frame + // << " - NQ: " << next_quarter_frame_to_send << " - FD" << quarter_frame_duration << endl; + + // FIXME: this should always be true + //assert((outbound_mtc_smpte_frame + (next_quarter_frame_to_send * quarter_frame_duration)) + // > _transport_frame); - // Send quarter frames up to current time - { - LockMonitor lm (midi_lock, __LINE__, __FILE__); + + // Send quarter frames for this cycle + while (_transport_frame + nframes > (outbound_mtc_smpte_frame + + (next_quarter_frame_to_send * quarter_frame_duration))) { + + // cerr << "(MTC) Next frame to send: " << next_quarter_frame_to_send << endl; - switch(next_quarter_frame_to_send) { + switch (next_quarter_frame_to_send) { case 0: mtc_msg[1] = 0x00 | (transmitting_smpte_time.frames & 0xf); break; @@ -985,31 +815,49 @@ Session::send_midi_time_code () case 7: mtc_msg[1] = 0x70 | (((mtc_smpte_bits|transmitting_smpte_time.hours) & 0xf0) >> 4); break; - } - - if (_mtc_port->midimsg (mtc_msg, 2)) { - error << string_compose(_("Session: cannot send quarter-frame MTC message (%1)"), strerror (errno)) - << endmsg; - - return -1; - } + } + + const nframes_t msg_time = (outbound_mtc_smpte_frame + + (quarter_frame_duration * next_quarter_frame_to_send)); + + // This message must fall within this block or something is broken + assert(msg_time >= _transport_frame); + assert(msg_time < _transport_frame + nframes); - // cout << "smpte = " << transmitting_smpte_time.hours << ":" << transmitting_smpte_time.minutes << ":" << transmitting_smpte_time.seconds << ":" << transmitting_smpte_time.frames << ", qfm = " << next_quarter_frame_to_send << endl; - - // Increment quarter frame counter - next_quarter_frame_to_send++; - - if (next_quarter_frame_to_send >= 8) { - // Wrap quarter frame counter - next_quarter_frame_to_send = 0; - // Increment smpte time twice - smpte_increment( transmitting_smpte_time ); - smpte_increment( transmitting_smpte_time ); - // Re-calculate timing of first quarter frame - smpte_to_sample( transmitting_smpte_time, outbound_mtc_smpte_frame, true /* use_offset */, false ); - } + nframes_t out_stamp = msg_time - _transport_frame; + assert(out_stamp < nframes); + + if (_mtc_port->midimsg (mtc_msg, 2, out_stamp)) { + error << string_compose(_("Session: cannot send quarter-frame MTC message (%1)"), strerror (errno)) + << endmsg; + return -1; + } + + /*cerr << "(MTC) SMPTE: " << transmitting_smpte_time.hours + << ":" << transmitting_smpte_time.minutes + << ":" << transmitting_smpte_time.seconds + << ":" << transmitting_smpte_time.frames + << ", qfm = " << next_quarter_frame_to_send + << ", stamp = " << out_stamp + << ", delta = " << _transport_frame + out_stamp - last_time << endl;*/ + + // Increment quarter frame counter + next_quarter_frame_to_send++; + + if (next_quarter_frame_to_send >= 8) { + // Wrap quarter frame counter + next_quarter_frame_to_send = 0; + // Increment smpte time twice + SMPTE::increment( transmitting_smpte_time ); + SMPTE::increment( transmitting_smpte_time ); + // Re-calculate timing of first quarter frame + //smpte_to_sample( transmitting_smpte_time, outbound_mtc_smpte_frame, true /* use_offset */, false ); + outbound_mtc_smpte_frame += 8 * quarter_frame_duration; + // Compensate for audio latency + outbound_mtc_smpte_frame += _worst_output_latency; } } + return 0; } @@ -1018,31 +866,14 @@ Session::send_midi_time_code () **********************************************************************/ void -Session::send_mmc_in_another_thread (MIDI::MachineControl::Command cmd, jack_nframes_t target_frame) -{ - MIDIRequest* request; - - if (_mtc_port == 0 || !send_mmc) { - return; - } - - request = new MIDIRequest; - request->type = MIDIRequest::SendMMC; - request->mmc_cmd = cmd; - request->locate_frame = target_frame; - - midi_requests.write (&request, 1); - poke_midi_thread (); -} - -void -Session::deliver_mmc (MIDI::MachineControl::Command cmd, jack_nframes_t where) +Session::deliver_mmc (MIDI::MachineControl::Command cmd, nframes_t where) { using namespace MIDI; int nbytes = 4; - SMPTE_Time smpte; + SMPTE::Time smpte; - if (_mmc_port == 0 || !send_mmc) { + if (_mmc_port == 0 || !session_send_mmc) { + // cerr << "Not delivering MMC " << _mmc_port << " - " << session_send_mmc << endl; return; } @@ -1068,6 +899,7 @@ Session::deliver_mmc (MIDI::MachineControl::Command cmd, jack_nframes_t where) case MachineControl::cmdPlay: /* always convert Play into Deferred Play */ + /* Why? [DR] */ mmc_buffer[4] = MachineControl::cmdDeferredPlay; break; @@ -1091,11 +923,9 @@ Session::deliver_mmc (MIDI::MachineControl::Command cmd, jack_nframes_t where) mmc_buffer[nbytes++] = 0xf7; // terminate SysEx/MMC message - LockMonitor lm (midi_lock, __LINE__, __FILE__); - - if (_mmc_port->write (mmc_buffer, nbytes) != nbytes) { + if (_mmc_port->midimsg (mmc_buffer, nbytes, 0)) { error << string_compose(_("MMC: cannot send command %1%2%3"), &hex, cmd, &dec) << endmsg; - } + } } } @@ -1128,66 +958,6 @@ Session::mmc_step_timeout () return true; } - -void -Session::send_midi_message (MIDI::Port * port, MIDI::eventType ev, MIDI::channel_t ch, MIDI::EventTwoBytes data) -{ - // in another thread, really - - MIDIRequest* request = new MIDIRequest; - - request->type = MIDIRequest::SendMessage; - request->port = port; - request->ev = ev; - request->chan = ch; - request->data = data; - - midi_requests.write (&request, 1); - poke_midi_thread (); -} - -void -Session::deliver_midi (MIDI::Port * port, MIDI::byte* buf, int32_t bufsize) -{ - // in another thread, really - - MIDIRequest* request = new MIDIRequest; - - request->type = MIDIRequest::Deliver; - request->port = port; - request->buf = buf; - request->size = bufsize; - - midi_requests.write (&request, 1); - poke_midi_thread (); -} - -void -Session::deliver_midi_message (MIDI::Port * port, MIDI::eventType ev, MIDI::channel_t ch, MIDI::EventTwoBytes data) -{ - if (port == 0 || ev == MIDI::none) { - return; - } - - midi_msg[0] = (ev & 0xF0) | (ch & 0xF); - midi_msg[1] = data.controller_number; - midi_msg[2] = data.value; - - port->write (midi_msg, 3); -} - -void -Session::deliver_data (MIDI::Port * port, MIDI::byte* buf, int32_t size) -{ - if (port) { - port->write (buf, size); - } - - /* this is part of the semantics of the Deliver request */ - - delete [] buf; -} - /*--------------------------------------------------------------------------- MIDI THREAD ---------------------------------------------------------------------------*/ @@ -1215,29 +985,30 @@ Session::start_midi_thread () return -1; } - // pthread_detach (midi_thread); - return 0; } void Session::terminate_midi_thread () { - MIDIRequest* request = new MIDIRequest; - void* status; + if (midi_thread) { - request->type = MIDIRequest::Quit; - - midi_requests.write (&request, 1); - poke_midi_thread (); + MIDIRequest* request = new MIDIRequest; + void* status; + + request->type = MIDIRequest::Quit; + + midi_requests.write (&request, 1); + poke_midi_thread (); - pthread_join (midi_thread, &status); + pthread_join (midi_thread, &status); + } } void Session::poke_midi_thread () { - char c; + static char c = 0; if (write (midi_request_pipe[1], &c, 1) != 1) { error << string_compose(_("cannot send signal to midi thread! (%1)"), strerror (errno)) << endmsg; @@ -1267,7 +1038,7 @@ Session::midi_thread_work () bool restart; vector ports; - PBD::ThreadCreated (pthread_self(), X_("MIDI")); + PBD::ThreadCreatedWithRequestSize (pthread_self(), X_("MIDI"), 2048); memset (&rtparam, 0, sizeof (rtparam)); rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */ @@ -1278,10 +1049,7 @@ Session::midi_thread_work () /* set up the port vector; 4 is the largest possible size for now */ - ports.push_back (0); - ports.push_back (0); - ports.push_back (0); - ports.push_back (0); + ports.assign (4, (MIDI::Port*) 0); while (1) { @@ -1291,11 +1059,7 @@ Session::midi_thread_work () pfd[nfds].events = POLLIN|POLLHUP|POLLERR; nfds++; - /* if we are using MMC control, we obviously have to listen - on the appropriate port. - */ - - if (mmc_control && _mmc_port && _mmc_port->selectable() >= 0) { + if (Config->get_mmc_control() && _mmc_port && _mmc_port->selectable() >= 0) { pfd[nfds].fd = _mmc_port->selectable(); pfd[nfds].events = POLLIN|POLLHUP|POLLERR; ports[nfds] = _mmc_port; @@ -1307,14 +1071,18 @@ Session::midi_thread_work () the relevant port. */ - if (_mtc_port && (_mtc_port != _mmc_port || !mmc_control) && _mtc_port->selectable() >= 0) { + if (_mtc_port && (_mtc_port != _mmc_port || !Config->get_mmc_control()) && _mtc_port->selectable() >= 0) { pfd[nfds].fd = _mtc_port->selectable(); pfd[nfds].events = POLLIN|POLLHUP|POLLERR; ports[nfds] = _mtc_port; nfds++; } - if (_midi_port && (_midi_port != _mmc_port || !mmc_control) && (_midi_port != _mtc_port) && _midi_port->selectable() >= 0) { + /* if we are using MMC control, we obviously have to listen + the relevant port. + */ + + if (_midi_port && (_midi_port != _mmc_port || !Config->get_mmc_control()) && (_midi_port != _mtc_port) && _midi_port->selectable() >= 0) { pfd[nfds].fd = _midi_port->selectable(); pfd[nfds].events = POLLIN|POLLHUP|POLLERR; ports[nfds] = _midi_port; @@ -1342,7 +1110,6 @@ Session::midi_thread_work () // cerr << "MIDI thread wakes at " << get_cycles () << endl; fds_ready = 0; - restart = false; /* check the transport request pipe */ @@ -1382,37 +1149,6 @@ Session::midi_thread_work () while (midi_requests.read (&request, 1) == 1) { switch (request->type) { - - case MIDIRequest::SendFullMTC: - // cerr << "send full MTC\n"; - send_full_time_code (); - // cerr << "... done\n"; - break; - - case MIDIRequest::SendMTC: - // cerr << "send qtr MTC\n"; - send_midi_time_code (); - // cerr << "... done\n"; - break; - - case MIDIRequest::SendMMC: - // cerr << "send MMC\n"; - deliver_mmc (request->mmc_cmd, request->locate_frame); - // cerr << "... done\n"; - break; - - case MIDIRequest::SendMessage: - // cerr << "send Message\n"; - deliver_midi_message (request->port, request->ev, request->chan, request->data); - // cerr << "... done\n"; - break; - - case MIDIRequest::Deliver: - // cerr << "deliver\n"; - deliver_data (_midi_port, request->buf, request->size); - // cerr << "... done\n"; - break; - case MIDIRequest::PortChange: /* restart poll with new ports */ // cerr << "rebind\n"; @@ -1449,7 +1185,7 @@ Session::midi_thread_work () if (pfd[p].revents & POLLIN) { fds_ready++; - midi_read (ports[p]); + ports[p]->parse (); } } @@ -1473,21 +1209,3 @@ Session::midi_thread_work () } } -bool -Session::get_mmc_control () const -{ - return mmc_control; -} -bool -Session::get_midi_feedback () const -{ - /* since this a "write" function we have to check the port as well - as the control toggle. - */ - return _midi_port && midi_feedback; -} -bool -Session::get_midi_control () const -{ - return midi_control; -}