From 39becbeb70aa4ab82b963669d87995a32141981c Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 21 Jun 2012 20:31:14 +0000 Subject: smooth 0.5 second fade out during quit, plus MIDI panic to turn everything off (someone will want an opton for that, no doubt) git-svn-id: svn://localhost/ardour2/branches/3.0@12814 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/audio_port.h | 3 ++ libs/ardour/ardour/audioengine.h | 8 +-- libs/ardour/audio_port.cc | 12 ++++- libs/ardour/audioengine.cc | 107 +++++++++++++++++++++++++++------------ libs/ardour/session_process.cc | 2 +- 5 files changed, 93 insertions(+), 39 deletions(-) (limited to 'libs/ardour') diff --git a/libs/ardour/ardour/audio_port.h b/libs/ardour/ardour/audio_port.h index 6b534afe62..7f084a5c85 100644 --- a/libs/ardour/ardour/audio_port.h +++ b/libs/ardour/ardour/audio_port.h @@ -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 diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index fdaf864a0d..73e40e8ab4 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -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; @@ -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 f; diff --git a/libs/ardour/audio_port.cc b/libs/ardour/audio_port.cc index 48a757fb42..240224ea5e 100644 --- a/libs/ardour/audio_port.cc +++ b/libs/ardour/audio_port.cc @@ -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); +} + + diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 5642db8932..004ba33a6e 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -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 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 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 ap = boost::dynamic_pointer_cast (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) { diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index 3936423b14..585d0927f2 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -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); -- cgit v1.2.3