Route::set_meter_point() is now conceptually RT safe, although it still takes a write...
authorPaul Davis <paul@linuxaudiosystems.com>
Mon, 7 Dec 2009 14:18:06 +0000 (14:18 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 7 Dec 2009 14:18:06 +0000 (14:18 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@6320 d708f5d6-7413-0410-9779-e7cbd77b26cf

libs/ardour/ardour/meter.h
libs/ardour/ardour/route.h
libs/ardour/ardour/track.h
libs/ardour/meter.cc
libs/ardour/route.cc
libs/ardour/session.cc
libs/ardour/session_events.cc
libs/ardour/session_midi.cc
libs/ardour/track.cc

index dbaba25a06a6c5d7ceeba018d2cb34b23b3ab5b0..ae0a1672dbf59609a3fe358a1b911146e979807e 100644 (file)
@@ -59,6 +59,19 @@ public:
 
        bool can_support_io_configuration (const ChanCount& in, ChanCount& out) const;
        bool configure_io (ChanCount in, ChanCount out);
+       
+       /* special method for meter, to ensure that it can always handle the maximum
+          number of streams in the route, no matter where we put it.
+       */
+
+       void reset_max_channels (const ChanCount&);
+
+       /* tell the meter than no matter how many channels it can handle,
+          `in' is the number it is actually going be handling from
+          now on.
+       */
+
+       void reflect_inputs (const ChanCount& in);
 
        /** Compute peaks */
        void run (BufferSet& bufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes, bool);
@@ -80,10 +93,12 @@ public:
        }
 
        XMLNode& state (bool full);
-
+       
 private:
        friend class IO;
-
+       
+       uint32_t current_meters;
+       
        std::vector<float> _peak_power;
        std::vector<float> _visible_peak_power;
        std::vector<float> _max_peak_power;
index 984ba5fe95b0a8158b26c08c6ea74cbf655750b4..8b08dded99f67543929bf306c3acf7d1d2b038ab 100644 (file)
@@ -153,7 +153,7 @@ class Route : public SessionObject, public AutomatableControls
        void       drop_route_group (void *);
        RouteGroup *route_group () const { return _route_group; }
 
-       virtual void set_meter_point (MeterPoint, void *src);
+       void         set_meter_point (MeterPoint, void *src);
        MeterPoint   meter_point() const { return _meter_point; }
        void         meter ();
 
index 82cb83ad165aa037eab180fe158b913d19e13de3..5d8e2dbbd5b284d434e68e3ada002cbe7b64316a 100644 (file)
@@ -90,8 +90,6 @@ class Track : public Route
        bool record_enabled() const;
        void set_record_enable (bool yn, void *src);
 
-       void set_meter_point (MeterPoint, void* src);
-
        sigc::signal<void> DiskstreamChanged;
        sigc::signal<void> FreezeChange;
 
index 0d3e8e228a941bc061ee3cb1453996846bd46734..4566ed7e0255a23bdfd182c98b1be76a8802312b 100644 (file)
@@ -65,6 +65,12 @@ Metering::update_meters()
        Meter(); /* EMIT SIGNAL */
 }
 
+PeakMeter::PeakMeter (Session& s, const XMLNode& node)
+       : Processor (s, node)
+{
+       current_meters = 0;
+}
+
 /** Get peaks from @a bufs
  * Input acceptance is lenient - the first n buffers from @a bufs will
  * be metered, where n was set by the last call to setup(), excess meters will
@@ -115,11 +121,6 @@ PeakMeter::run (BufferSet& bufs, sframes_t /*start_frame*/, sframes_t /*end_fram
        _active = _pending_active;
 }
 
-PeakMeter::PeakMeter (Session& s, const XMLNode& node)
-       : Processor (s, node)
-{
-}
-
 void
 PeakMeter::reset ()
 {
@@ -150,7 +151,21 @@ PeakMeter::configure_io (ChanCount in, ChanCount out)
                return false;
        }
 
-       uint32_t limit = in.n_total();
+       current_meters = in.n_total ();
+
+       return Processor::configure_io (in, out);
+}
+
+void
+PeakMeter::reflect_inputs (const ChanCount& in)
+{
+       current_meters = in.n_total ();
+}
+
+void
+PeakMeter::reset_max_channels (const ChanCount& chn)
+{
+       uint32_t limit = chn.n_total();
 
        while (_peak_power.size() > limit) {
                _peak_power.pop_back();
@@ -167,8 +182,6 @@ PeakMeter::configure_io (ChanCount in, ChanCount out)
        assert(_peak_power.size() == limit);
        assert(_visible_peak_power.size() == limit);
        assert(_max_peak_power.size() == limit);
-
-       return Processor::configure_io (in, out);
 }
 
 /** To be driven by the Meter signal from IO.
@@ -185,7 +198,7 @@ PeakMeter::meter ()
 
        assert(_visible_peak_power.size() == _peak_power.size());
 
-       const size_t limit = _peak_power.size();
+       const size_t limit = min (_peak_power.size(), (size_t) current_meters);
 
        for (size_t n = 0; n < limit; ++n) {
 
index 6879eee5e52fe4ada43ef1e0af4f016992df3d4c..768df386988b615f53fae63e46c063de2a5b5948 100644 (file)
@@ -80,8 +80,8 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        /* add standard processors other than amp (added by ::init()) */
 
        _meter.reset (new PeakMeter (_session));
-       _meter->set_display_to_user (_meter_point == MeterCustom);
-       add_processor (_meter, PreFader);
+       _meter->set_display_to_user (false);
+       add_processor (_meter, PostFader);
 
        if (_flags & ControlOut) {
                /* where we listen to tracks */
@@ -1479,6 +1479,10 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
                out = c->second;
        }
 
+       if (_meter) {
+               _meter->reset_max_channels (processor_max_streams);
+       }
+
        /* make sure we have sufficient scratch buffers to cope with the new processor
           configuration */
        _session.ensure_buffers (n_process_buffers ());
@@ -2667,6 +2671,8 @@ Route::flush_processors ()
 void
 Route::set_meter_point (MeterPoint p, void *src)
 {
+       /* CAN BE CALLED FROM PROCESS CONTEXT */
+
        if (_meter_point == p) {
                return;
        }
@@ -2675,54 +2681,61 @@ Route::set_meter_point (MeterPoint p, void *src)
 
        {
                Glib::RWLock::WriterLock lm (_processor_lock);
-               ProcessorList as_it_was (_processors);
-
+       
                if (p != MeterCustom) {
                        // Move meter in the processors list to reflect the new position
-                       ProcessorList::iterator loc = find(_processors.begin(), _processors.end(), _meter);
+                       ProcessorList::iterator loc = find (_processors.begin(), _processors.end(), _meter);
                        _processors.erase(loc);
                        switch (p) {
                        case MeterInput:
                                loc = _processors.begin();
                                break;
                        case MeterPreFader:
-                               loc = find(_processors.begin(), _processors.end(), _amp);
+                               loc = find (_processors.begin(), _processors.end(), _amp);
                                break;
                        case MeterPostFader:
                                loc = _processors.end();
                                break;
                        default:
-                       break;
+                               break;
                        }
-
-                       _processors.insert(loc, _meter);
                        
-                       if (configure_processors_unlocked (0)) {
-                               _processors = as_it_was;
-                               configure_processors_unlocked (0); // it worked before we tried to add it ...
-                               return;
+                       ChanCount m_in;
+                       
+                       if (loc == _processors.begin()) {
+                               m_in = _input->n_ports();
+                       } else {
+                               ProcessorList::iterator before = loc;
+                               --before;
+                               m_in = (*before)->output_streams ();
                        }
-
+                       
+                       _meter->reflect_inputs (m_in);
+                       
+                       _processors.insert (loc, _meter);
+                       
+                       /* we do not need to reconfigure the processors, because the meter
+                          (a) is always ready to handle processor_max_streams
+                          (b) is always an N-in/N-out processor, and thus moving
+                          it doesn't require any changes to the other processors.
+                       */
+                       
                        _meter->set_display_to_user (false);
-
+                       
                } else {
-
+                       
                        // just make it visible and let the user move it
-
+                       
                        _meter->set_display_to_user (true);
                }
-               
        }
 
        _meter_point = p;
        meter_change (src); /* EMIT SIGNAL */
 
-       /* the meter has visibly changed if it is not visible to the user, or if it was and now isn't */
-       bool const meter_visibly_changed = _meter->display_to_user() || meter_was_visible_to_user;
+       bool const meter_visibly_changed = (_meter->display_to_user() != meter_was_visible_to_user);
        
        processors_changed (RouteProcessorChange (RouteProcessorChange::MeterPointChange, meter_visibly_changed)); /* EMIT SIGNAL */
-               
-       _session.set_dirty ();
 }
 
 void
index 9cb4cc32849506a0fd00e14bd0c2afc1ad76e658..f113bf4ebc995d0585b247c9bf97460e982ecd94 100644 (file)
@@ -1164,8 +1164,9 @@ Session::disable_record (bool rt_context, bool force)
                // FIXME: timestamp correct? [DR]
                // FIXME FIXME FIXME: rt_context?  this must be called in the process thread.
                // does this /need/ to be sent in all cases?
-               if (rt_context)
+               if (rt_context) {
                        deliver_mmc (MIDI::MachineControl::cmdRecordExit, _transport_frame);
+               }
 
                if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) {
                        boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
@@ -3647,13 +3648,21 @@ Session::record_enable_change_all (bool yn)
 void
 Session::do_record_enable_change_all (RouteList* rl, bool yn)
 {
-       for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+       for (RouteList::iterator i = rl->begin(); i != rl->end(); ) {
                boost::shared_ptr<Track> t;
 
                if ((t = boost::dynamic_pointer_cast<Track>(*i)) != 0) {
                        t->set_record_enable (yn, this);
-               }
+                       if (t->meter_point() == MeterCustom) {
+                               /* don't change metering for this track */
+                               i = rl->erase (i);
+                       } else {
+                               ++i;
+                       }
+               } 
        }
+
+       set_dirty ();
 }
 
 void
index 8818436ed76081b01b77a0f47bdba0108a07b7aa..7b24b1abef82c4124daf17e77839f43ba3681bdd 100644 (file)
@@ -69,7 +69,7 @@ SessionEvent::operator delete (void *ptr, size_t /*size*/)
 {
        Pool* p = pool->per_thread_pool ();
        SessionEvent* ev = static_cast<SessionEvent*> (ptr);
-       
+
        if (p == ev->own_pool) {
                p->release (ptr);
        } else {
@@ -278,3 +278,10 @@ SessionEventManager::_clear_event_type (SessionEvent::Type type)
        set_next_event ();
 }
 
+#if 0
+void
+Session::process_rtop (SessionEvent* ev)
+{
+       ev->rt_return (ev->rt_slot ());
+}
+#endif
index 15777aa642ab02f1f6314efbcd0e4328996fecc3..a0366dd6e88f41e77f3188e2719f715207709ff0 100644 (file)
@@ -1082,6 +1082,227 @@ Session::_midi_thread_work (void* arg)
        return 0;
 }
 
+#if 0
+void
+Session::midi_thread_work ()
+{
+       MIDIRequest* request;
+       GPollFD pfd[4];
+       int nfds = 0;
+       int timeout;
+       int fds_ready;
+       struct sched_param rtparam;
+       int x;
+       bool restart;
+       vector<MIDI::Port*> ports;
+
+       PBD::notify_gui_about_thread_creation (pthread_self(), X_("MIDI"), 2048);
+       SessionEvent::create_per_thread_pool (X_("MIDI I/O"), 128);
+
+       memset (&rtparam, 0, sizeof (rtparam));
+       rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
+
+       if ((x = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
+               // do we care? not particularly.
+       }
+
+       /* set up the port vector; 5 is the largest possible size for now */
+
+       ports.assign (5, (MIDI::Port*) 0);
+
+       GMainContext* main_context = g_main_context_new ();
+
+       while (1) {
+
+               nfds = 0;
+
+               gpfd[nfds].fd = midi_request_pipe[0];
+               gpfd[nfds].events = POLLIN|POLLHUP|POLLERR;
+               nfds++;
+
+               if (Config->get_mmc_control() && _mmc_port && _mmc_port->selectable() >= 0) {
+                       gpfd[nfds].fd = _mmc_port->selectable();
+                       gpfd[nfds].events = POLLIN|POLLHUP|POLLERR;
+                       ports[nfds] = _mmc_port;
+                       g_main_context_add_poll (&gpfd[nfds]);
+                       DEBUG_TRACE (DEBUG::MidiIO, string_compose ("set up port #%1 for mmc @ %2\n", nfds, _mmc_port));
+                       nfds++;
+               }
+
+               /* if MTC is being handled on a different port from MMC
+                  or we are not handling MMC at all, poll
+                  the relevant port.
+               */
+
+               if (_mtc_port && (_mtc_port != _mmc_port || !Config->get_mmc_control()) && _mtc_port->selectable() >= 0) {
+                       gpfd[nfds].fd = _mtc_port->selectable();
+                       gpfd[nfds].events = POLLIN|POLLHUP|POLLERR;
+                       ports[nfds] = _mtc_port;
+                       g_main_context_add_poll (&gpfd[nfds]);
+                       DEBUG_TRACE (DEBUG::MidiIO, string_compose ("set up port #%1 for mtc @ %2\n", nfds, _mtc_port));
+                       nfds++;
+               }
+
+               if (_midi_clock_port && (_midi_clock_port != _mmc_port || !Config->get_mmc_control()) && _midi_clock_port->selectable() >= 0) {
+                       gpfd[nfds].fd = _midi_clock_port->selectable();
+                       gpfd[nfds].events = POLLIN|POLLHUP|POLLERR;
+                       ports[nfds] = _midi_clock_port;
+                       g_main_context_add_poll (&gpfd[nfds]);
+                       DEBUG_TRACE (DEBUG::MidiIO, string_compose ("set up port #%1 for midi clock @ %2\n", nfds, _midi_clock_port));
+                       nfds++;
+               }
+
+               /* 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) {
+                       gpfd[nfds].fd = _midi_port->selectable();
+                       gpfd[nfds].events = POLLIN|POLLHUP|POLLERR;
+                       ports[nfds] = _midi_port;
+                       g_main_context_add_poll (&gpfd[nfds]);
+                       DEBUG_TRACE (DEBUG::MidiIO, string_compose ("set up port #%1 for midi @ %2\n", nfds, _midi_port));
+                       nfds++;
+               }
+
+               if (!midi_timeouts.empty()) {
+                       timeout = 100; /* 10msecs */
+               } else {
+                       timeout = -1; /* if there is no data, we don't care */
+               }
+
+         again:
+
+               DEBUG_TRACE (DEBUG::MidiIO, string_compose ("MIDI poll on %1 fds for %2\n", nfds, timeout));
+               if (g_poll (gpfd, nfds, timeout) < 0) {
+                       if (errno == EINTR) {
+                               /* gdb at work, perhaps */
+                               goto again;
+                       }
+
+                       error << string_compose(_("MIDI thread poll failed (%1)"), strerror (errno)) << endmsg;
+
+                       break;
+               }
+
+               nframes64_t now = engine().frame_time();
+
+               DEBUG_TRACE (DEBUG::MidiIO, "MIDI thread awake\n");
+
+               fds_ready = 0;
+
+               /* check the transport request pipe */
+
+               if (gpfd[0].revents & ~POLLIN) {
+                       error << _("Error on transport thread request pipe") << endmsg;
+                       break;
+               }
+
+               if (gpfd[0].revents & POLLIN) {
+
+                       char foo[16];
+                       
+                       DEBUG_TRACE (DEBUG::MidiIO, "MIDI request FIFO ready\n");
+                       fds_ready++;
+
+                       /* empty the pipe of all current requests */
+
+                       while (1) {
+                               size_t nread = read (midi_request_pipe[0], &foo, sizeof (foo));
+
+                               if (nread > 0) {
+                                       if ((size_t) nread < sizeof (foo)) {
+                                               break;
+                                       } else {
+                                               continue;
+                                       }
+                               } else if (nread == 0) {
+                                       break;
+                               } else if (errno == EAGAIN) {
+                                       break;
+                               } else {
+                                       fatal << _("Error reading from transport request pipe") << endmsg;
+                                       /*NOTREACHED*/
+                               }
+                       }
+
+                       while (midi_requests.read (&request, 1) == 1) {
+
+                               switch (request->type) {
+                               case MIDIRequest::PortChange:
+                                       /* restart poll with new ports */
+                                       DEBUG_TRACE (DEBUG::MidiIO, "rebind\n");
+                                       restart = true;
+                                       break;
+
+                               case MIDIRequest::Quit:
+                                       delete request;
+                                       DEBUG_TRACE (DEBUG::MidiIO, "thread quit\n");
+                                       pthread_exit_pbd (0);
+                                       /*NOTREACHED*/
+                                       break;
+
+                               default:
+                                       break;
+                               }
+
+
+                               delete request;
+                       }
+
+               }
+
+               if (restart) {
+                       DEBUG_TRACE (DEBUG::MidiIO, "ports changed, restart poll\n");
+                       restart = false;
+                       continue;
+               }
+
+               /* now read the rest of the ports */
+
+               for (int p = 1; p < nfds; ++p) {
+
+                       DEBUG_STR_SET(foo, "port #%1 revents = ");
+                       DEBUG_STR(foo) << hex << pfd[p].revents << dec << endl;
+                       DEBUG_TRACE (DEBUG::MidiIO, string_compose (DEBUG_STR(foo).str(), p));
+
+                       if ((pfd[p].revents & ~POLLIN)) {
+                               // error << string_compose(_("Transport: error polling MIDI port %1 (revents =%2%3%4"), p, &hex, pfd[p].revents, &dec) << endmsg;
+                               break;
+                       }
+
+                       if (pfd[p].revents & POLLIN) {
+                               DEBUG_TRACE (DEBUG::MidiIO, string_compose ("MIDI fd # %1 has data ready @ %2\n", p, now));
+                               fds_ready++;
+                               ports[p]->parse (now);
+                       }
+
+                       g_main_context_remove_poll (&gpfd[p]);
+               }
+
+               /* timeout driven */
+
+               if (fds_ready < 2 && timeout != -1) {
+
+                       DEBUG_TRACE (DEBUG::MidiIO, "Check timeouts\n");
+                       for (MidiTimeoutList::iterator i = midi_timeouts.begin(); i != midi_timeouts.end(); ) {
+
+                               MidiTimeoutList::iterator tmp;
+                               tmp = i;
+                               ++tmp;
+
+                               if (!(*i)()) {
+                                       midi_timeouts.erase (i);
+                               }
+
+                               i = tmp;
+                       }
+               }
+       }
+
+}
+#endif
+
 void
 Session::midi_thread_work ()
 {
index acf0c50e1881995c21a0398fe9ad7674bad2a8aa..373829413ceaa336003f3741c1ffa77c32910f60 100644 (file)
@@ -66,12 +66,6 @@ Track::~Track ()
        DEBUG_TRACE (DEBUG::Destruction, string_compose ("track %1 destructor\n", _name));
 }
 
-void
-Track::set_meter_point (MeterPoint p, void *src)
-{
-       Route::set_meter_point (p, src);
-}
-
 XMLNode&
 Track::get_state ()
 {
@@ -192,17 +186,15 @@ Track::set_record_enable (bool yn, void *src)
 
        _diskstream->set_record_enabled (yn);
 
-#if 0
        if (_diskstream->record_enabled()) {
-               set_meter_point (MeterInput, this);
+               if (_meter_point != MeterCustom) {
+                       set_meter_point (MeterInput, this);
+               }
        } else {
                set_meter_point (_saved_meter_point, this);
        }
-#endif
 
-       cerr << "4\n";
        _rec_enable_control->Changed ();
-       cerr << "5\n";
 }