smooth 0.5 second fade out during quit, plus MIDI panic to turn everything off (someo...
authorPaul Davis <paul@linuxaudiosystems.com>
Thu, 21 Jun 2012 20:31:14 +0000 (20:31 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Thu, 21 Jun 2012 20:31:14 +0000 (20:31 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@12814 d708f5d6-7413-0410-9779-e7cbd77b26cf

gtk2_ardour/ardour_ui.cc
libs/ardour/ardour/audio_port.h
libs/ardour/ardour/audioengine.h
libs/ardour/audio_port.cc
libs/ardour/audioengine.cc
libs/ardour/session_process.cc

index 0a4a4782d2b4f8e426f7f6aabef6e0823bf0f0d8..e41f71235114296f24ed3d6fb04cc459936ca308 100644 (file)
@@ -755,11 +755,6 @@ ARDOUR_UI::finish()
        if (_session) {
                int tries = 0;
 
-               if (_session->transport_rolling() && (++tries < 8)) {
-                       _session->request_stop (false, true);
-                       usleep (10000);
-               }
-
                if (_session->dirty()) {
                        vector<string> actions;
                        actions.push_back (_("Don't quit"));
index 6b534afe621f43f9447667adae157cdd2820b303..7f084a5c85fb12d56897cb384fa242f6d614b745 100644 (file)
@@ -49,9 +49,12 @@ class AudioPort : public Port
        friend class AudioEngine;
 
        AudioPort (std::string const &, Flags);
+        /* special access for engine only */
+        Sample* engine_get_whole_audio_buffer ();
 
   private:
        AudioBuffer* _buffer;
+        bool         _buf_valid; 
 };
 
 } // namespace ARDOUR
index fdaf864a0d4430e7310db46c0f15444b44a3a7b9..73e40e8ab4abe39adbe3291dc31064bd850fc767 100644 (file)
@@ -268,6 +268,9 @@ private:
        Glib::Mutex               _process_lock;
        Glib::Cond                 session_removed;
        bool                       session_remove_pending;
+        frameoffset_t              session_removal_countdown;
+        gain_t                     session_removal_gain;
+        gain_t                     session_removal_gain_step;
        bool                      _running;
        bool                      _has_run;
        mutable framecnt_t        _buffer_size;
@@ -283,6 +286,8 @@ private:
        bool                      _pre_freewheel_mmc_enabled;
        int                       _usecs_per_cycle;
        bool                       port_remove_in_progress;
+       Glib::Thread*              m_meter_thread;
+       ProcessThread*            _main_thread;
 
        SerializedRCUManager<Ports> ports;
 
@@ -331,11 +336,8 @@ private:
        void start_metering_thread ();
        void stop_metering_thread ();
 
-       Glib::Thread*    m_meter_thread;
        static gint      m_meter_exit;
 
-       ProcessThread* _main_thread;
-
        struct ThreadData {
                AudioEngine* engine;
                boost::function<void()> f;
index 48a757fb42ca1d0143c2f314677e43a3eb174966..240224ea5e5b33112ae3e72f5e6c21ca5851eac8 100644 (file)
@@ -73,10 +73,18 @@ AudioBuffer&
 AudioPort::get_audio_buffer (pframes_t nframes)
 {
        /* caller must hold process lock */
-       _buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes) +
-                          _global_port_buffer_offset + _port_buffer_offset, nframes);
+       _buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes) +
+                          _global_port_buffer_offset + _port_buffer_offset, nframes);
        return *_buffer;
 }
 
+Sample* 
+AudioPort::engine_get_whole_audio_buffer ()
+{
+       /* caller must hold process lock */
+       return (Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes);
+}
+
+
 
 
index 5642db89321dd8cb90f7dfbc09cf9b36ec2d0c65..004ba33a6e235e4bc98731cee347d927ff5bf765 100644 (file)
@@ -62,26 +62,26 @@ AudioEngine* AudioEngine::_instance = 0;
 #define GET_PRIVATE_JACK_POINTER_RET(j,r) jack_client_t* _priv_jack = (jack_client_t*) (j); if (!_priv_jack) { return r; }
 
 AudioEngine::AudioEngine (string client_name, string session_uuid)
-       : ports (new Ports)
+       : _jack (0)
+       , session_remove_pending (false)
+       , session_removal_countdown (-1)
+       , _running (false)
+       , _has_run (false)
+       , _buffer_size (0)
+       , _frame_rate (0)
+       , monitor_check_interval (INT32_MAX)
+       , last_monitor_check (0)
+       , _processed_frames (0)
+       , _freewheeling (false)
+       , _pre_freewheel_mmc_enabled (false)
+       , _usecs_per_cycle (0)
+       , port_remove_in_progress (false)
+       , m_meter_thread (0)
+       , _main_thread (0)
+       , ports (new Ports)
 {
        _instance = this; /* singleton */
 
-       session_remove_pending = false;
-       _running = false;
-       _has_run = false;
-       last_monitor_check = 0;
-       monitor_check_interval = INT32_MAX;
-       _processed_frames = 0;
-       _usecs_per_cycle = 0;
-       _jack = 0;
-       _frame_rate = 0;
-       _buffer_size = 0;
-       _freewheeling = false;
-       _pre_freewheel_mmc_enabled = false;
-        _main_thread = 0;
-       port_remove_in_progress = false;
-
-       m_meter_thread = 0;
        g_atomic_int_set (&m_meter_exit, 0);
 
        if (connect_to_jack (client_name, session_uuid)) {
@@ -476,28 +476,43 @@ AudioEngine::process_callback (pframes_t nframes)
        }
 
        if (session_remove_pending) {
+
                /* perform the actual session removal */
-               _session = 0;
-               session_remove_pending = false;
 
-               /* pump one cycle of silence into the ports
-                  before the session tears them all down
-                  (asynchronously).
-               */
+               if (session_removal_countdown < 0) {
 
-               boost::shared_ptr<Ports> p = ports.reader();
-               
-               for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-                       
-                       if (i->second->sends_output()) {
-                               i->second->get_buffer (nframes).silence (nframes);
+                       /* fade out over 1 second */
+                       session_removal_countdown = _frame_rate/2;
+                       session_removal_gain = 1.0;
+                       session_removal_gain_step = 1.0/session_removal_countdown;
+
+               } else if (session_removal_countdown > 0) {
+
+                       /* we'll be fading audio out.
+                          
+                          if this is the last time we do this as part 
+                          of session removal, do a MIDI panic now
+                          to get MIDI stopped. This relies on the fact
+                          that "immediate data" (aka "out of band data") from
+                          MIDI tracks is *appended* after any other data, 
+                          so that it emerges after any outbound note ons, etc.
+                       */
+
+                       if (session_removal_countdown <= nframes) {
+                               _session->midi_panic ();
                        }
-               }
 
-               session_removed.signal();
+               } else {
+                       /* fade out done */
+                       _session = 0;
+                       session_removal_countdown = -1; // reset to "not in progress"
+                       session_remove_pending = false;
+                       session_removed.signal(); // wakes up thread that initiated session removal
+               }
        }
 
        if (_session == 0) {
+
                if (!_freewheeling) {
                        MIDI::Manager::instance()->cycle_start(nframes);
                        MIDI::Manager::instance()->cycle_end();
@@ -574,8 +589,6 @@ AudioEngine::process_callback (pframes_t nframes)
 
        if (_session->silent()) {
 
-               boost::shared_ptr<Ports> p = ports.reader();
-
                for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
 
                        if (i->second->sends_output()) {
@@ -584,6 +597,34 @@ AudioEngine::process_callback (pframes_t nframes)
                }
        }
 
+       if (session_remove_pending && session_removal_countdown) {
+
+               for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
+
+                       if (i->second->sends_output()) {
+
+                               boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
+                               if (ap) {
+                                       Sample* s = ap->engine_get_whole_audio_buffer ();
+                                       gain_t g = session_removal_gain;
+                                       
+                                       for (pframes_t n = 0; n < nframes; ++n) {
+                                               *s++ *= g;
+                                               g -= session_removal_gain_step;
+                                       }
+                               }
+                       }
+               }
+               
+               if (session_removal_countdown > nframes) {
+                       session_removal_countdown -= nframes;
+               } else {
+                       session_removal_countdown = 0;
+               }
+
+               session_removal_gain -= (nframes * session_removal_gain_step);
+       }
+
        // Finalize ports
 
        for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
index 3936423b141a98e46ffc0cb09504e5bbe0bfd894..585d0927f27fd0311817ce4edb749d85d9fab74c 100644 (file)
@@ -158,7 +158,7 @@ Session::process_routes (pframes_t nframes, bool& need_butler)
 
        const framepos_t start_frame = _transport_frame;
        const framepos_t end_frame = _transport_frame + floor (nframes * _transport_speed);
-
+       
        if (_process_graph) {
                DEBUG_TRACE(DEBUG::ProcessThreads,"calling graph/process-routes\n");
                _process_graph->process_routes (nframes, start_frame, end_frame, declick, need_butler);