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
This commit is contained in:
Paul Davis 2012-06-21 20:31:14 +00:00
parent 33d17f176b
commit 39becbeb70
6 changed files with 93 additions and 44 deletions

View file

@ -755,11 +755,6 @@ ARDOUR_UI::finish()
if (_session) { if (_session) {
int tries = 0; int tries = 0;
if (_session->transport_rolling() && (++tries < 8)) {
_session->request_stop (false, true);
usleep (10000);
}
if (_session->dirty()) { if (_session->dirty()) {
vector<string> actions; vector<string> actions;
actions.push_back (_("Don't quit")); actions.push_back (_("Don't quit"));

View file

@ -49,9 +49,12 @@ class AudioPort : public Port
friend class AudioEngine; friend class AudioEngine;
AudioPort (std::string const &, Flags); AudioPort (std::string const &, Flags);
/* special access for engine only */
Sample* engine_get_whole_audio_buffer ();
private: private:
AudioBuffer* _buffer; AudioBuffer* _buffer;
bool _buf_valid;
}; };
} // namespace ARDOUR } // namespace ARDOUR

View file

@ -268,6 +268,9 @@ private:
Glib::Mutex _process_lock; Glib::Mutex _process_lock;
Glib::Cond session_removed; Glib::Cond session_removed;
bool session_remove_pending; bool session_remove_pending;
frameoffset_t session_removal_countdown;
gain_t session_removal_gain;
gain_t session_removal_gain_step;
bool _running; bool _running;
bool _has_run; bool _has_run;
mutable framecnt_t _buffer_size; mutable framecnt_t _buffer_size;
@ -283,6 +286,8 @@ private:
bool _pre_freewheel_mmc_enabled; bool _pre_freewheel_mmc_enabled;
int _usecs_per_cycle; int _usecs_per_cycle;
bool port_remove_in_progress; bool port_remove_in_progress;
Glib::Thread* m_meter_thread;
ProcessThread* _main_thread;
SerializedRCUManager<Ports> ports; SerializedRCUManager<Ports> ports;
@ -331,11 +336,8 @@ private:
void start_metering_thread (); void start_metering_thread ();
void stop_metering_thread (); void stop_metering_thread ();
Glib::Thread* m_meter_thread;
static gint m_meter_exit; static gint m_meter_exit;
ProcessThread* _main_thread;
struct ThreadData { struct ThreadData {
AudioEngine* engine; AudioEngine* engine;
boost::function<void()> f; boost::function<void()> f;

View file

@ -73,10 +73,18 @@ AudioBuffer&
AudioPort::get_audio_buffer (pframes_t nframes) AudioPort::get_audio_buffer (pframes_t nframes)
{ {
/* caller must hold process lock */ /* caller must hold process lock */
_buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes) + _buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes) +
_global_port_buffer_offset + _port_buffer_offset, nframes); _global_port_buffer_offset + _port_buffer_offset, nframes);
return *_buffer; return *_buffer;
} }
Sample*
AudioPort::engine_get_whole_audio_buffer ()
{
/* caller must hold process lock */
return (Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes);
}

View 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; } #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) 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 */ _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); g_atomic_int_set (&m_meter_exit, 0);
if (connect_to_jack (client_name, session_uuid)) { if (connect_to_jack (client_name, session_uuid)) {
@ -476,28 +476,43 @@ AudioEngine::process_callback (pframes_t nframes)
} }
if (session_remove_pending) { if (session_remove_pending) {
/* perform the actual session removal */ /* perform the actual session removal */
_session = 0;
session_remove_pending = false;
/* pump one cycle of silence into the ports if (session_removal_countdown < 0) {
before the session tears them all down
(asynchronously).
*/
boost::shared_ptr<Ports> p = ports.reader(); /* fade out over 1 second */
session_removal_countdown = _frame_rate/2;
for (Ports::iterator i = p->begin(); i != p->end(); ++i) { session_removal_gain = 1.0;
session_removal_gain_step = 1.0/session_removal_countdown;
if (i->second->sends_output()) {
i->second->get_buffer (nframes).silence (nframes); } 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 (_session == 0) {
if (!_freewheeling) { if (!_freewheeling) {
MIDI::Manager::instance()->cycle_start(nframes); MIDI::Manager::instance()->cycle_start(nframes);
MIDI::Manager::instance()->cycle_end(); MIDI::Manager::instance()->cycle_end();
@ -574,8 +589,6 @@ AudioEngine::process_callback (pframes_t nframes)
if (_session->silent()) { if (_session->silent()) {
boost::shared_ptr<Ports> p = ports.reader();
for (Ports::iterator i = p->begin(); i != p->end(); ++i) { for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
if (i->second->sends_output()) { 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 // Finalize ports
for (Ports::iterator i = p->begin(); i != p->end(); ++i) { for (Ports::iterator i = p->begin(); i != p->end(); ++i) {

View file

@ -158,7 +158,7 @@ Session::process_routes (pframes_t nframes, bool& need_butler)
const framepos_t start_frame = _transport_frame; const framepos_t start_frame = _transport_frame;
const framepos_t end_frame = _transport_frame + floor (nframes * _transport_speed); const framepos_t end_frame = _transport_frame + floor (nframes * _transport_speed);
if (_process_graph) { if (_process_graph) {
DEBUG_TRACE(DEBUG::ProcessThreads,"calling graph/process-routes\n"); DEBUG_TRACE(DEBUG::ProcessThreads,"calling graph/process-routes\n");
_process_graph->process_routes (nframes, start_frame, end_frame, declick, need_butler); _process_graph->process_routes (nframes, start_frame, end_frame, declick, need_butler);